File: ecgitut.txt

package info (click to toggle)
libecgi 0.6.2-2.2
  • links: PTS
  • area: main
  • in suites: woody
  • size: 4,004 kB
  • ctags: 307
  • sloc: ansic: 1,781; makefile: 126; sh: 13; xml: 7
file content (1341 lines) | stat: -rw-r--r-- 52,239 bytes parent folder | download | duplicates (2)
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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
eCgiLib 0.6 
Documentation & Manual
Index

1 Introduction	4
1.1 What is eCgiLib ?	4
1.2 History	4
1.3 Maintainer/Contact	5
1.4 Licence	5
1.5 Remarks	5
1.6 Todo	6
2 CGI Basics	7
2.1 Basic CGI Communication	7
2.1.1 Data Input	7
2.1.1.1 CGI independent environment Vars	7
2.1.1.2 CGI dependent Input	7
2.1.1.2.1 the GET Method	7
2.1.1.2.2 the simple POST Method	8
2.1.1.2.3 the multipart/form-data POST Method	8
2.1.2 Data output	9
2.1.2.1 The Header	9
2.1.2.2 The Data	9
2.2 Advanced CGI Programming	9
2.2.1 Cookies	9
2.2.2 Hidden Input Fields	9
2.2.3 Actions	10
2.2.4 Session Keys	10
2.2.5 Databases	10
2.2.6 HTML Templates	10
3 eCgiLib Usage	11
3.1 basics	11
3.1.1 cgiInit()	11
3.1.2 cgiDone()	11
3.1.3 cgiParam() - the main function	11
3.1.4 cgiStrError()	12
3.1.5 Compatibility to version <= 0.5	12
3.2 File Uploads	13
3.2.1 basic concept	13
3.2.2 The filename and the Content-Type	13
3.2.3 3 Kinds of Elements	13
3.2.3.1 cgiKindValue	13
3.2.3.2 cgiKindEmptyFile	13
3.2.3.3 cgiKindFileToBig	14
3.2.3.4 cgiKindFile	14
3.2.4 Accessing the Files	14
3.2.4.1 cgiGetMFile()	14
3.2.4.2 cgiMFileToFile()	14
3.2.5 limits	14
3.2.5.1 cgiSetMaxFileSize()	14
3.2.5.2 cgiSetMaxSize()	14
3.3 Accessing Elements without the knowing the name	15
3.3.1 Why?	15
3.3.2 Access to Elements using cgiGetFirstName() / cgiGetNextName()	15
3.3.3 Access to Elements using cgiPosNext()	15
3.3.4 cgiNameByValue()	16
3.4 Memory Files	16
3.4.1 Basic concept	16
3.4.2 "usual" c file functions and memory files	17
3.4.3 additional memory file functions	17
3.4.3.1 mfMFileToFile()	17
3.4.3.2 mfFileToMFile()/mfFileToMFileN()	17
3.4.3.3 mfGetData()	17
3.4.3.4 mfGetDataAt()	18
3.4.3.5 mfSetLength()	18
3.4.3.6 mfGetLength()	18
3.5 Saving/Loading the environment for simple debugging	18
3.5.1 cgiSaveDebugData()	18
3.5.2 cgiLoadDebugData()	18
3.6 eCgi Toolkit	18
3.6.1 ctkRedirect()	18
3.6.2 ctkGetSessionID()	19
3.6.3 ctkTimeToHDate()	19
3.6.4 ctkHDateToTime()	19
3.7 HTML Preprozessor	19
3.7.1 Basic concept	19
3.7.2 Example	20
3.7.3 Section Tag	23
3.7.4 Param Tag	24
3.7.4 Slink Tag	24
3.7.4 Comments	24
4 eCgiLib Function Library	25
4.1 ecgi.h	25
4.2 memfile.h	26
4.3 ecgi-internal.h - not for the user!	27
Appendix A - Demo Programms	30
A1 Simple-Demo	30
Demo1.html	30
Demo1.c	30
A2 Multi Form Demo / All Data access Demo / Template Demo:	30
html/enter.h	30
html/pageTwo.h	31
html/pageThree.h	31
demo2.c	31


1 Introduction

1.1 What is eCgiLib ?

eCgiLib (= easy CGI Libary) is a simple to use c cgi libary based on cgic. It transparently supports the CGI Method GET and POST and also multipart/form-data file uploads. The user interface is designed as easy as possible and maintains full compatibility to cgic 0.5, from which it is derived
It also contains a libary independend introduction to CGI programming with C, a .html to .h HTML template preprozessor and fast block allocating "memory files"

It was written after needing file upload, searching the web, and finding NO usable c cgi libary, which support all mentioned things AND a easy interface. Course i used cgic 0.5 before, and knew Todor Prokopov <koprok@newmail.net> stopped developing it further, i used his work - and his multipart tests, which he send me. Thanks man!

1.2 History

*****************
* NOW TESTED ON *
*****************

- linux glibc 2.1 gcc 2.95.2
- solaris7 gcc 2.95.2

***********************
* SOURCE CODE CHANGES *
***********************

0.6.2
-----
- added comments headers to files - juhuu!
- copied gpl to doc/COPYING
- fixed bug in html2h - input files where also parsed in comments
13.02.2001
- there was only ONE untouched function from cgic 0.5 left in my ecgi lib,
  and this bastard function had an segfault in it (which occured only
  VERY rarely) - thanks to "Bao C. Ha" <bao@hacom.net> for showing me.
  (who also maintains a ecgi debian package now ...)
- fixed a bug in memfile.h, where i used a "va_list *ap" instead of a
  "va_list ap" - how silly ...
  thanks to Ramon Poca <ramon@tau.uab.es> for telling me
- ecgitk uses time.h - added an "#include <time.h>", so you dont have to
  include it in your programm

0.6.1
------
08.12.2000
- compiled now on solaris - fixed some segfaulting typecasts.
- added: html2h preprozessor now finds HTML input tags and adds them to
  the .h header - so you allways know, what names to ask for with cgiParam(),
  when getting input from a template
- "ANSI-CLEANED" the sources by changing some things after invoking gcc
  with -ansi and -pedantic - changed all // to /* .. */ - ANSI-PROVED now :)
- cleaned up Makefile - ie: if the "gcc --shared" fails now, this happens
  as the last thing - should not make any real problems, since libecgi.a
  should be generated then
- replaced setenv() with putenv() in loadDebugData(), because setenv is not
  supported on solaris (why ever)
- read basics about "autoconf" and decided NOT to do this myself, since my
  focus is c-programming!

0.6 Initial Release 
-------------------
December 2000
- rewrote complete source from Todor Prokopov - only 1 untouched function 
  in the sources - added new functions for file handling, for accessing all 
  objects without the name and saving/loading the whole environment for 
  debugging.
06.12.2000
- added mfFileToMFileN()
- cgiLoadDebugData() and cgiSaveDebugData() functions work now
- mfprintf()  added to memory files
- added "make install" to the Makefile (it creates a .a ar 
  archive and a .so lib now)
- html2h preprozessor added
- added first functions to ecgitk - eCgiToolkit 

*************************
* Documentation Changes *
*************************

13.02.2000
- added example to cgiInit() documentation, since i got an email with a
  segfault while calling the cgi from bash

06.12.2000
- documented mfFileToMFileN() - see 3.4.3.2
- updated cgiLoadDebugData() and cgiSaveDebugData() documentation (3.5.1 and 3.5.2)
- added mfprintf() without further documentation to 3.4.2
- updated chapter 3.6 ecgi Toolkit
- added chapter 3.7 html2h HTML preprozessor

December 2000
- wrote first version

1.3 Maintainer/Contact

Thats me! Sven Dawitz - Sven@Dawitz.de. The web adress for ecgi is http://www.Global-OWL.de/ecgi
If you want to contact me, feel free to do so!

1.4 Licence

This Software is under GPL. Blah Blah Blah ...
You have the sources. Just do with it, what you want.
It would be nice, if you drop me an email, if you use it. Just to see, who finds it useful. Perhaps i will add a "Used by" section later.

1.5 Remarks

Put this documentation to professional english. Copy Dahl promised me to do so, if he is available for it. So currently, remeber that i am no natural english speaking guy and have my problems with putting it really professional - but the information itself should be ok ...
If someone else, who is naturally speaking english, read this - perhaps you could edit it and fix up my language. 

If you try file uploading, but it fails: check your proxy settings - squid for example only allows upload till 1MB at all - to find out, my program doesnt segfault, but isnt even executed took me about 6 hours of work - upside: i rewrote much code for it and made it (hopefully) segfault secure.
1.6 Todo

- check all malloc/realloc calls for returning NULL - memory at end
- really USE maxfilesize and maxsize - currently dont do anything
- implement the cgiSaveDebugData()/cgiLoadDebugData() - currently they write an error to stdout and exit the program ... not good ...
- check error defines - some are obsolete / others must be added
- think about defining max name size due security (a 150mb name would be fun)
- integrate mad sql libary ...
- integrate ecgitk lib
- test if you can use fread/fseek on stdin to speed up reading
  doesn work with popen files, so i guess, wont work with stdin, too
  but have to check! Block reads would be really nice!

2 CGI Basics

2.1 Basic CGI Communication


2.1.1 Data Input
The user submits Data via the browser to the web server, who calls the program. There are two main kinds of input to our programm:

2.1.1.1 CGI independent environment Vars

The web server sets environment vars, which contain misc information about the client, like "REMOTE_ADDR" for the remote ip adress, "REMOTE_HOST" for the remote hostname, "SCRIPT" for the script name and others. You can get these environment variables with getenv(). Dump the whole environment variables with a little test programm to see more. These are not part of ecgi. (Or at least, most of them). And they are extremly server and browser dependend.

2.1.1.2 CGI dependent Input
This describes the ways, the CGI programm can get input from the user - There are three ways for that.
Ecgilib handles all transparent for you - you dont need to know how that works. This is just info about the things behind ecgilib.

2.1.1.2.1 the GET Method
The data is send in the URL - you might have seen this before:

http://foo.bar/whatever.cgi?field1=this+is+test+data&field2=any%20other%20data

This is a simple Method - and the only method, you can use with links - for the others, you need a real form, with datafields and at least one submit button. So you will need GET when having many links on your page, which all do something else.
The web server puts this data (after the ?) to the environment variable "QUERY_STRING" where ecgilib reads and parses it. 
The GET Method is detected by the environment variable REQUEST_METHOD which is set to "GET".
As far as i know, this method has a maximum length somewhere - but i am neither sure, nor do i know, where this limit is. If you know, email me.

2.1.1.2.2 the simple POST Method

The data is encrypted the same way than in the GET Method:

field1=this+is+test+data&field2=any%20other%20data

But the Web Server writes it to STDIN instead of writing it to a environment variable. You need a real form with <FORM ACTION="script.cgi" METHOD="POST"> and a submit button for this method.
The POST Method is detected by the environment variable REQUEST_METHOD set to "POST" and CONTENT_TYPE set to "application/x-www-form-urlencoded".
With using stdin, this method has no limits i am aware of.

2.1.1.2.3 the multipart/form-data POST Method

This method was created, when realizing, that the usual GET/POST methods were not able to send binary data. So multipart/form-data was born, which uses MIME encryption like:

Content-tpye: mulitpart/form-data; boundary=xyz4711
--xyz4711
content-disposition: form-data; name="username"

Joe Blow
--xyz4711
content-disposition: form-data; name="file-upload"; filename="c:\command.com"
Content-Type: unknown/unknown

Binary data here ff 00 xx yy ...
--xyz4711
content-disposition: form-data; name="multiline-field"

This is
The multiline
Field test
--xyz4711--

For Input, STDIN is used again. if we have a <FORM ACTION="script.cgi" METHOD="POST"  ENCTYPE="multipart/form-data"> we can use a <INPUT TYPE="FILE" NAME="file"> inside this form to upload any files (text files AND binary files)
The method is detected by the environment variable REQUEST_METHOD set to "POST" and CONTENT_TYPE starting with "multipart/form-data".

2.1.2 Data output

The result from the program is simply sent to stdout - in two parts, which are seperated by an empty line

2.1.2.1 The Header

Without an Header, the webserver will produce an internal server error. The Header has to be at least "Content-Type: text/html" followed by two returns.
In the header, you can set some more items, like telling the browser/proxies not to cache the site, redirecting the browser to another url by a "Location: http://new.url.com", setting cookies and other stuff. 
The data submitted in the header is not shown to the user.
Read the HTTP documentation for more info on this.

2.1.2.2 The Data

This is simply the HTML Page itself, which is rendered by the browser and displayed to the user. Use simple HTML syntax here.

2.2 Advanced CGI Programming

This Chapter shortly gives tips for creating larger cgi programs. It is only a short list of items which can be used. It mainly focuses on the fact, that when having two (or more) pages (ie first page like login with username and password, second page enter some data), the programm is called once for any pages submitted - so you have to exchange data between these two pages. If you dont use any technics here, your programm wont know about the username on the second page.
Make sure to read the demo programms which are in the appendix.
2.2.1 Cookies

This is an "old" method - mainly used by javascript programms, which run on the client. 
You can use cookies to save data on the client. This is protected by the second domain name, so "www.domain.com" and "shop.domain.com" can access the same cookie, which is marked as "domain.com". They can not access cookies from "other-domain.com".
The data saved is limited to 40k (as far as i remeber).
Since many security problems with cookies were found, the new browsers can be set to ask you for any cookie before accepting it. Some firewalls completly disallow cookies.
So dont use this method if you are not absolutly sure what you are doing.
Remark: Cookies are not yet supported by ecgi. Perhaps a later version will support it in the toolkit.
2.2.2 Hidden Input Fields

A commonly used technic to save data from one form to the next is using hidden input fields like with <input type="hidden" name="username" value="john doe"> or <input type="hidden" name="password" value="secret">. So the data entered on one form will be printed on the other form. You will need hidden input fields for the following methods. There is not disadvantage of using this. Only remeber that a "bad user" might create his own form, which he sends to your server. So check all input.
2.2.3 Actions

If you have one programm, which generates various pages, you must verify, which action is called now. Take a hidden input field like <input type="hidden" name="action" value"3"> for it. If you are in the main function, you can read the action variable, if it is empty, display the enter page, if not, call the function associated with this value. Read the demo in appendix for an simple example.
2.2.4 Session Keys

This is one of the best technics i know of. When the user enters, you assign a unique session id to him. To make it unique, take the time, the remote address and the remote port - this combination must be unique according to tcp/ip.
Format it as characters, so it is a little crypted.
From now on, ALLWAYS keep the session key as a hidden field. So you can fill shoppers, save any other data of this session without cookies. You can also add an expire data, when the session times out - and an expire idle date, when the session times out when the user not longer accesses you (you must update a last access field for this of course - use databases!)
If you use frames/layers generated by your cgi programm, you should redirect him, if he enters. Else, if he hits reload, you could loose his session id.
2.2.5 Databases

Not much to say about it, just: use them! You can use databases extremly well for all kind of cgi. Else, you have to write to tmp files on your own.

2.2.6 HTML Templates

I usually use html templates to write resulting pages. So you dont have html in your sources, where it probably shouldnt be, but only in external html includes. If you wanna change the layout, you dont have to change the sources. Read the demo for an example.
Caution: if you use tables with lists of data, you have to split the html include in something like "head" / "row" / "foot" - or even more. I am currently working on a preprozessor, so you keep your old html files and only add comments for the preprozessor - which generates your .h file from the .html file. This way, you can allways edit your html file with a html editor and dont have to care about the output.
Advanced tip: For big programs, think about putting the templates in a database, too. So you can change the layout without recompiling the source. You can even add an option to let the user change layout while using the program (if you have more than one layout in your database)


3 eCgiLib Usage
3.1 basics

Here i will put the basic command to ecgi. If you dont use File Upload, this is probably all you need - only 3 functions: cgiInit()/cgiDone() at start/end of programm and cgiParam() for accessing the data. Cgic <=0.5 ONLY had these functions. Thats why it was intended by Todor to call it EASY cgi.
3.1.1 cgiInit()

int cgiInit();

Call this function before accessing anything else. It will parse the input from the server to the program and create an internal list of elements. Only call this function once.
The only functions which may be called before cgiInit are cgiSetMaxFileSize() and cgiSetMaxSize() to set the maximum limit of memory used by ecgiLib (see below)
If the init fails for any reson, the function returns false and sets cgi_errno. You can call cgiStrError() then to get the error.

Call it this way. Else, you might get segfaults, when calling the program from the shell directly!

If(cgiInit()!=ECGI_SUCCESS){
	printf("ERROR: %s\n", cgiStrError(cgi_errno));
	exit(cgi_errno);
}
3.1.2 cgiDone()

void cgiDone();

Call this function before exiting the programm. Will free all memory occupied by cgiInit().
Note: since most unix systems free all used memory of a program, when this program exits, you must not call cgiDone. Depending on the specific unix system, which you use, it might be faster just to exit and let the system free the memory.
3.1.3 cgiParam() - the main function

const char *cgiParam(const char *name);

This will probably be your most called function. I take the explation of Todor Prokopov here, which is very good:
Use the `cgiParam' function to grab the HTML form entry value, with a
given name, for example:

    char *color;
    ...
    color = cgiParam("color");

This function returns NULL, if there isn't an entry with the given name,
passed to the program, so after calling it, you should check that:

    if (color == NULL)
    {
      /* There isn't an entry called "color", passed to us. */
      ...
    }

In instances of multiple values, associated with the same entry name, repeated
use of `cgiParam' with the same entry name cycles through all it's values,
associated with the given name. The return of a null pointer indicates the end
of the cycle. If you need to retrieve the first value instance again, you need
to reset the function. Do this by passing a null pointer, as a parameter to it.
For example, let's assume we have the following entries:

    fruit=apple
    fruit=pear

 The first call `cgiParam("fruit")' returns "apple", the second returns
"pear", the third, fourth and so on returns NULL. If you wish to retrieve the
first value ("apple") again, first reset the function by calling
`cgiParam(NULL)', and then the call `cgiParam("fruit")' returns "apple"
again.
The `cgiParam()' function is reset also by invoking it with another entry
name, not the same as that, you have asked the last time. For example if you
have the following entries, passed:

    fruit=apple
    fruit=pear
    vegetables=potato

 Invoking `cgiParam("fruit")' for the first time gives "apple", the second
call `cgiParam("vegetables")' returns "potato" and if you call it again like
this `cgiParam("fruit")', you get "apple" again, not "pear"! If you call
`cgiParam("fruit")' one more time, then you get "pear".

NOTE: You should not modify the string returned by `cgiParam'. If you have
to modify it, first copy it to another piece of memory, using `strdup' or
something similar.
3.1.4 cgiStrError()

const char*	cgiStrError(int errnum);

call this, if cgiInit() returns false, which indicates an error:

	if(cgiInit()==false){
		printf("An Error occured: %s", cgiStrError(cgi_errno));
		exit(cgi_errno);
	}
3.1.5 Compatibility to version <= 0.5

You might have noticed, that the function names changed. For example, cgi_init() now is called cgiInit(). This naming system is used for all functions now. To stay compatible with the old names, there are some precompiler macros. So the old sources still run with the new lib.
Its just, i personally prefer the case separtion for names than the underscore stuff.
3.2 File Uploads
3.2.1 basic concept

The basic concept for fileuploads it NOT to write the files to any temporary directory, but to the memory. This is done, because writing to a directory will probably bring up security problems. Overwriting existing files, files readable for everyone etc. Reading in memory is a problem, too (you could send REAL big files for DOS attacks). Thats, why i implemented a limit (by default unlimited)
Remember once again: If you do a file upload, the memory is free'd as soon as the result is sent to the user again and NOT during the whole session. So memory usage should be no problem. Its in the hands of the programmer (YES, thats you!). eCgi only provides the tools.
Perhaps i will add an option to write them directly to a directory - even i dont see any need for this now.
3.2.2 The filename and the Content-Type

const char *cgiGetCTyp(const char *name);

the filename can be obtained by a simple cgiParam() call - it is treated like a usual value. The content type can be obtained by a cgiGetCType() call.
Note that both - the file name and the content type - are extremly browser dependend. For example an upload of "/etc/passwd" with netscape for linux will result in filename "passwd" content type "text/plain". The upload of "C:\autoexec.bat" with Microsoft Internet Explorer for Windows will result in filename "C:\autoexec.bat" with content-type "dont-remeber-gotta-test:)"
3.2.3 3 Kinds of Elements

With the cgiGetKind() function, you can get the kind of a cgi element by the name. There are four kinds.
3.2.3.1 cgiKindValue

#define CgiKindValue	 1

Usual Name/Value Pair send with normal HTML datafields. Just use cgiParam for those.
3.2.3.2 cgiKindEmptyFile

#define CgiKindFileEmpty 3

An Empty file has been sent.

This can have two reasons:
- No File selected by the user.
- The selected file was only 0bytes long

You can probably check this, when checking if a filename is set. If filename is NOT set, there was no file selected. if it is set, the file was 0byte.
Note: this is browser depended - some browsers perhaps wont send a filename in some cases - so you can NOT check, if it is empty or not selected anymore
3.2.3.3 cgiKindFileToBig

#define CgiKindFileToBig 4

the file uploaded has exceeded one of the limits set with the limit functions (see below).
3.2.3.4 cgiKindFile

#define CgiKindFile 2

Here we finally have a real file.
You can get the Memory File with cgiGetMFile() (see below), or you can directly dump the file to a real file with cgiMFileToFile()
3.2.4 Accessing the Files
3.2.4.1 cgiGetMFile()

MFILE* cgiGetMFile(const char *name);

Calling this function with the name as attribute (see cgiParam()) returns a Pointer to the Memory File MFILE* (see below for handling of memoryfiles)
3.2.4.2 cgiMFileToFile()

int cgiMFileToFile(const char *name, const char *fname, const char *fopenmode);

This function writes the file from memory to your local hard disk. Call it  with the fname to write to, and the open mode (see "man fopen" for details of openmode)
Note: memory is NOT free'd by this. You must call mfclose to do so.
3.2.5 limits

As mentioned above, you can set limits to the memory used for file uploads to prevent DOS attacks.
Once one of the Limits is overrun, the kind is set to cgiKindFileToBig. The other cgi elements are processed as usual.
3.2.5.1 cgiSetMaxFileSize()

void cgiSetMaxFileSize(int size);

This functions sets the maximum amount of memory used for a single file.
3.2.5.2 cgiSetMaxSize()

void cgiSetMaxSize(int size);

Since a form can have more than one file upload fields, this functions sets the maximum amount of memory which can be used for all file uploads.
3.3 Accessing Elements without the knowing the name
3.3.1 Why?

Some might say: "You allways know the name, course you are the programmer" - right, but there are some cases, you do NOT know them.
Imagine a tool for sending mails (like formmail.pl does) - you can set a hidden filed "needed" which has the names of the fields which may not be empty. If all fields are filled, you send an email to the adress in "mailto". If you can access all elements, you could easily write such a variable tool. Thats only ONE point where i needed these functions in the past.
There are two general ways of accessing the internal list of elements.
3.3.2 Access to Elements using cgiGetFirstName() / cgiGetNextName()

const char* cgiGetFirstName();
const char*	cgiGetNextName();

cgiGetFirstName returns the name of the first element - or NULL if no element  found - and sets an internal pointer to the last returned name.
CgiGetNextName returns the next - or NULL if there is no next name.

Since you can access all cgi functions by the name, this is one way of getting all elements. 

Example:

	const char *val;
	printf("%s\n", cgiGetFirstName());
	while((val=cgiGetNextName())!=NULL)
		printf("%s\n", val);
3.3.3 Access to Elements using cgiPosNext()

typedef	void CgiPos;
CgiPos*		cgiPosNext(CgiPos *lastpos);
const char*	cgiPosParam(CgiPos *where);
const char*	cgiPosName(CgiPos *where);
int			cgiPosGetKind(CgiPos *where);
const char*	cgiPosGetCTyp(CgiPos *where);
MFILE*		cgiPosGetMFile(CgiPos *where);
int			cgiPosMFileToFile(CgiPos *where, const char *fname, const char *fopenmode);

The function cgiPosNext() returns a pointer to the first element if called with parameter NULL, or to the next if you give the last return value.
With the CgiPos *, you can access all the cgi functions like accessing them by name. (In fact, the name functions internally use these functions. So using the CgiPos* pointer might be slightly faster)

An example should show the usage:

	CgiPos *p=NULL;
	while((p=cgiPosNext(p))!=NULL){
		printf("%s : ", cgiPosName(p));
		while((val=cgiPosParam(p))!=NULL)
			printf("%s ", val);
		if(cgiPosGetKind(p)==cgiKindFile)
			printf("This is an file!");
		printf("\n");
	}
3.3.4 cgiNameByValue()

const char*	cgiNameByValue(char *value);

This function returns the name of an element by give the value. Might be usefull in some cases. If called multiple, it acts like cgiParam() and returns all names containing this value, returning NULL when not finding any more.

Example:

	while((name=cgiNameByValue("test"))!=NULL)
		printf("%s\n", name);
3.4 Memory Files
3.4.1 Basic concept

The memoryfiles are not only the representative of the uploaded files, but heavily used internal for dynamic allocation. Since they dont call realloc every added byte, but allocate blocks of bytes (is defined in memfile.h - default=4k Blocks), they are the fast way to dynamic memory.
You can use this files for everything, which requires much allocation like:

	char *buf=NULL;
	FILE *f=fopen("whatever", "r");
	int c, size=0;

	While((c=fgetc(f))!=EOF){
		buf=realloc(buf, size+1);
		buf[size++]=c;
	}

In such a case, you should use the memfiles - and their feature of block allocation. This should be faster, since malloc/realloc is commonly slow.

	FILE *f=fopen("whatever", "r");
	MFILE *mf=mfopen();
	int c;

	while((c=fgetc(f))!=EOF)
		mfputc(c, mf);

Now you can access the data with all the mf-functions.
3.4.2 "usual" c file functions and memory files

MFILE*		mfopen();
void		mfclose(MFILE *mf);
int			mfseek(MFILE *mf, int offset, int whence);
int 		mftell(MFILE *mf);
int 		mfeof(MFILE *mf);
int 		mfread(void *data, int times, int length, MFILE *mf);
int 		mfwrite(void *data, int times, int length, MFILE *mf);
int 		mfgetc(MFILE *mf);
int 		mfputc(unsigned char c, MFILE *mf);
int			mfprintf(MFILE *mf, const char *format, ...);

If you are a c-programmer (hope you are, why else you read this ???), you know these functions. They are exactly what the functions without the leading m are - like mfopen() is the pedant to fopen(), mfseek() is the pedant to fseek(). If you dont know them, just read the c documentation (like "man fseek")
Differences: 
mfopen() doesnt get any filename, openmode - i think, its obvious why :)
mfclose() free's all memory used by the file - dont access this pointer after mfclose()
3.4.3 additional memory file functions

Since this are not REAL Files, we have some more (usefull?) functions.
3.4.3.1 mfMFileToFile()

int 		mfMFileToFile(MFILE *mf, FILE *f);

Appends a MFile to a given File Handle.
Use cgiMFileToFile() for simple dumping.
Note: it APPENDS it to the current position of the cursor in the file. (see "man fopen", "man fseek")
3.4.3.2 mfFileToMFile()/mfFileToMFileN()

int 		mfFileToMFile(FILE *f, MFILE *mf);
int			mfFileToMFileN(FILE *f, MFILE *mf, int count);

Appends a File to a given MFile.
Use the mfFileToMFileN(), if you dont want the whole file to be appended.
Note: it APPENDS it to the current position of the cursor in the MFile (see mfseek)
3.4.3.3 mfGetData()

const char*	mfGetData(MFILE *mf);

Returns the data of the file. The data is terminated by 0 at the end of the file, so you can use 

	printf("%s", mfGetData(myfile));

to dump the data. Remeber: if it is a binary file, it might look very ugly.
3.4.3.4 mfGetDataAt()

const char*	mfGetDataAt(MFILE *mf, int start);

same as mfGetData(), but only returns data from start byte. String also NULL Terminated.
3.4.3.5 mfSetLength()

int		mfSetLength(MFILE *mf, int length);

For resetting a file to 0 bytes, or any other length. This does not free the used memory, if you set it to 0 bytes. Use mfclose()/mfopen() to free memory. If you set the length bigger than old filesize, data is reallocated.
3.4.3.6 mfGetLength()

int 		mfGetLength(MFILE *mf);

returns the length of the file - so you dont have to get it with

	mfseek(mf, 0, SEEK_SET);
	size=mftell(mf);
3.5 Saving/Loading the environment for simple debugging
3.5.1 cgiSaveDebugData()

int cgiSaveDebugData(char *fname, char *fopenmode);

Call cgiSaveDebugData() after cgiInit(). This will dump the whole internal list of data plus all the environment variables to a file, which can be later loaded.
3.5.2 cgiLoadDebugData()

int cgiLoadDebugData(char *fname);

Call cgiLoadDebugData() instead of cgiInit() - after calling this, all environment variables and all cgi elements are restored to the state, they have been with cgiInit() when saving the data.
You can now debug your program from the console instead of using a webbrowser.
3.6 eCgi Toolkit

I will add a cgi Toolkit in "ecgitk.h" which is independend from ecgi.h, but includes commonly used functions which you need when programming cgi programms - like creating a unique session key or reading/saving cookies. I will put here functions, which I personally need, or things users request.
3.6.1 ctkRedirect()

int ctkRedirect(const char *format, ...);

This functions redirects the browser to another url. To make this work, you may NOT have printed anything to stdout yet, because this is done with the header.
If you redirect does not start with "http:", the server name is added to the redirect target to make sure the browser propperly shows the new url, since some browsers have problems with this when getting a relativ url.

Example:

ctkRedirekt("%s?action=%d&sessionid=%s", getenv("SCRIPT_NAME"), ActShowList, cgiParam("sessionid"));
3.6.2 ctkGetSessionID()

const char *ctkGetSessionID();

Returns a unique session id build from the time, the remote ip adress and the remote port. Data put to characters to crypt data a little.
Returned value must be free'd with free()
 
3.6.3 ctkTimeToHDate()

const char *ctkTimeToHDate(time_t time);

Constructs a asci date from the given time. Currently only in DD.MM.YYYY format.
Returned value must be free'd with free()
3.6.4 ctkHDateToTime()

time_t ctkHDateToTime(const char *hdate);
vice versa of ctkTimeToHDate() - returns a time_t record constructed from a input in format DD.MM.YYYY
Retruns 0, if the given date was in wrong format.
3.7 HTML Preprozessor

3.7.1 Basic concept

In the html2h/ subdir, you will find a binary called html2h, which is the first quick version of a html preprozessor. This is my first way of transparently use the html files as .h templates in a c programm AND still having the old .html file, which can be edited in a program like dreamweaver. The problem was, you have to split the html file in various substrings, delete some rows, you need for the layout, but not for the template and adding quick links to the script. Make sure, you read and understand my concept of html templates (2.2.6) and read the example at Appendix A2, which shows the usage of templates.
html2h parses the tags for it - starting with <!--# -, replaces " with \" and replaces % with %%. You need this as input for printf().

3.7.2 Example

Since it is complicate, to explain what html2h does, without seeing it, here an simple example (which is also included in the html2h/ directory)

Input: demo-simple.html

<!--#Section htmlSimpleHead 'Header of Simple demo file'-->
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body bgcolor="#FFFFFF" text="#000000">
<form name="form1" method="post" action="<!--#param s script 'Script Name'-->">
  <p>Hello <!--#param s name 'Name of logged in User'-->! </p>
  <p>Your Phonenumber: 
    <input type="text" name="phone" value="<!--#param s phone 'Phone Number'-->>
    <br>
    Select Area: 
    <select name="areaselect">
<!--#Section htmlSimpleSelectRow 'The select box items - one row for every possible'-->
      <option <!--#Param s selected 'Write SELECTED here, if selected'-->><!--#Param 30s katname 'Area Name - bound to right'--></option>
<!--#/*-->
      <option>hong kong</option>
      <option>japan</option>
      <option>home</option>
<!--#*/-->
<!--#Section htmlSimpleSelectBody-->
    </select>
  </p>
  <p>Current Numbers:</p>
  <table width="400" border="0" cellpadding="4">
    <tr> 
      <td>Number</td>
      <td>Area</td>
      <td> 
        <div align="center">Delete</div>
      </td>
      <td> 
        <div align="center">Edit</div>
      </td>
    </tr>
<!--#Section htmlSimplePhoneRow 'This lists all existing entries'-->
    <tr> 
      <td><!--#param s number 'Phone Number as string'--></td>
      <td><!--#param s area 'Area of number'--></td>
      <td> 
        <div align="center"><a href="<!--#SLink 'Link to Delete Entry' s skey 'Session ID' d eid 'ID of the specific entry'-->">-&gt;X&lt;-</a></div>
      </td>
      <td> 
        <div align="center"><a href="<!--#SLink 'Link to Edit this Entry' s skey 'Session ID' d eid-->-&gt;X&lt;-</a></div>
      </td>
    </tr>
<!--#Section htmlSimpleFoot-->
<!--#/*-->
    <tr> 
      <td>234233</td>
      <td>Home</td>
      <td> 
        <div align="center"><a href="x">-&gt;X&lt;-</a></div>
      </td>
      <td> 
        <div align="center"><a href="x">-&gt;X&lt;-</a></div>
      </td>
    </tr>
    <tr> 
      <td>342523</td>
      <td>japan</td>
      <td> 
        <div align="center"><a href="x">-&gt;X&lt;-</a></div>
      </td>
      <td> 
        <div align="center"><a href="x">-&gt;X&lt;-</a></div>
      </td>
    </tr>
<!--#*/-->
  </table>
  <p> 
    <input type="submit" name="Submit" value="Submit">
    <input type="reset" name="Submit2" value="Reset">
  </p>
</form>
</body>
</html>

Output: demo-simple.h

/****************************************************
 *       Header file generated with html2h 0.1      *
 *            (c) 2000 by Sven@Dawitz.de            *
 ****************************************************


----------------------------------------
htmlSimpleHead                   "Header of Simple demo file"
----------------------------------------
FORMAT     NAME                 COMMENT
----------------------------------------
s          script               "Script Name"
s          name                 "Name of logged in User"
s          phone                "Phone Number"


----------------------------------------
htmlSimpleSelectRow              "The select box items - one row for every possible"
----------------------------------------
FORMAT     NAME                 COMMENT
----------------------------------------
s          selected             "Write SELECTED here, if selected"
30s        katname              "Area Name - bound to right"


----------------------------------------
htmlSimpleSelectBody            
----------------------------------------
FORMAT     NAME                 COMMENT
----------------------------------------


----------------------------------------
htmlSimplePhoneRow               "This lists all existing entries"
----------------------------------------
FORMAT     NAME                 COMMENT
----------------------------------------
s          number               "Phone Number as string"
s          area                 "Area of number"
           ***SCRIPT LINK***    "Link to Delete Entry"
s               script               "Script Name"
s               skey                 "Session ID"
d               eid                  "ID of the specific entry"
           ***SCRIPT LINK***    "Link to Edit this Entry"
s               script               "Script Name"
s               skey                 "Session ID"
d               eid                 


----------------------------------------
htmlSimpleFoot                  
----------------------------------------
FORMAT     NAME                 COMMENT
----------------------------------------

 ****************************************************/


const char htmlSimpleHead[]="
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">
</head>

<body bgcolor=\"#FFFFFF\" text=\"#000000\">
<form name=\"form1\" method=\"post\" action=\"%s\">
  <p>Hello %s! </p>
  <p>Your Phonenumber: 
    <input type=\"text\" name=\"phone\" value=\"%s>
    <br>
    Select Area: 
    <select name=\"areaselect\">

";

const char htmlSimpleSelectRow[]="
      <option %s>%30s</option>


";

const char htmlSimpleSelectBody[]="
    </select>
  </p>
  <p>Current Numbers:</p>
  <table width=\"400\" border=\"0\" cellpadding=\"4\">
    <tr> 
      <td>Number</td>
      <td>Area</td>
      <td> 
        <div align=\"center\">Delete</div>
      </td>
      <td> 
        <div align=\"center\">Edit</div>
      </td>
    </tr>

";

const char htmlSimplePhoneRow[]="
    <tr> 
      <td>%s</td>
      <td>%s</td>
      <td> 
        <div align=\"center\"><a href=\"%s?skey=%s&eid=%d\">-&gt;X&lt;-</a></div>
      </td>
      <td> 
        <div align=\"center\"><a href=\"%s?skey=%s&eid=%d-&gt;X&lt;-</a></div>
      </td>
    </tr>

";

const char htmlSimpleFoot[]="

  </table>
  <p> 
    <input type=\"submit\" name=\"Submit\" value=\"Submit\">
    <input type=\"reset\" name=\"Submit2\" value=\"Reset\">
  </p>
</form>
</body>
</html>
";
3.7.3 Section Tag

<!--#section name ['comment']-->

The section tag will create a const char name[] entry for every section generated. You need a section before any html data. The comment is optional.

<!--#section htmlHead 'this is just a demo'-->
html stuff here 
<!--#section htmlRow 'this is the next row'-->

would result in

const char htmlHead[]="
html stuff here
";

const char htmlRow[]="...
3.7.4 Param Tag

<!--#param format name ['comment']-->

format is a printf format. 

<!--#param 10.3f floatvar--> 

would result in 

%10.3f

3.7.4 Slink Tag

<!--#slink format name1 ['comment'] format name2 ['comment'] ... format name3 ['comment'] -->

Use this, if you link to the script with varous parameters.

<!--#slink s skey 'session ID' d action 'ActShowStats' s user--> 

would result in

%s?skey=%s&action=%d&user=%s

3.7.4 Comments

<!--#/*--> not printed in .h file <!--#*/-->

These are the comment tags - link in c. html2h supports multi nested comments.

4 eCgiLib Function Library

Here are the header files of ecgi lib. The Usage should be obvious after reading chapter 3.

4.1 ecgi.h
The only file you need to include from your programm. Auto includes memfile.h, course you need it, too.

#define CgiKindValue	 1
#define CgiKindFile	 2
#define CgiKindFileEmpty 3

typedef	void CgiPos;

/****************************************
 * OLD FUNCTION NAMES FOR COMPATIBILITY *
 ****************************************/
#define	cgi_init()	cgiInit()
#define cgi_param(name) cgiParam(name)
#define cgi_done()	cgiDone()
#define cgi_strerror(no) cgiStrError(no)

/*****************************************
 * TRADITIONAL FUNCTIONS OF OLD CGIC 0.5 *
 *****************************************/
int 		cgiInit();
const char*	cgiParam(const char *name);
void		cgiDone();
const char*	cgiStrError(int errnum);

/*******************************
 * NEW FILE DEPENDED FUNCTIONS *
 *******************************/
void		cgiSetMaxFileSize(int size);
void 		cgiSetMaxSize(int size);
int			cgiGetKind(const char *name);
const char*	cgiGetCTyp(const char *name);
MFILE*		cgiGetMFile(const char *name);
int			cgiMFileToFile(const char *name, const char *fname, const char *fopenmode);

/****************************
 * MISC OTHER NEW FUNCTIONS *
 ****************************/
const char*	cgiNameByValue(char *value);

/**********************************************************
 * FUNCTION FOR GETTING ALL DATA WITHOUT KNOWING THE NAME *
 **********************************************************/
const char*	cgiGetFirstName();
const char*	cgiGetNextName();
CgiPos*		cgiPosNext(CgiPos *lastpos);
const char*	cgiPosParam(CgiPos *where);
const char*	cgiPosName(CgiPos *where);
int			cgiPosGetKind(CgiPos *where);
const char*	cgiPosGetCTyp(CgiPos *where);
MFILE*		cgiPosGetMFile(CgiPos *where);
int			cgiPosMFileToFile(CgiPos *where, const char *fname, const char *fopenmode);

/*****************************************************************
 * FUNCTIONS FOR SAVING/LOADING ENVIRONMENT - GOOD FOR DEBUGGING *
 *****************************************************************/
int		cgiSaveDebugData(char *fname, char *fopenmode);
int		cgiLoadDebugData(char *fname);

/* the error number */
extern int cgi_errno;

4.2 memfile.h
This is the interface for the memory files. Again: should be compatible with the usual f-functions.

#define MFILE_BLOCK 4096	// in what block should mem be increased

#ifndef true
	#define true	(1==1)
	#define false	(0==1)
#endif

typedef struct S_MFILE{
	void *data;

	int blocks;
	int eof;
	int used;
	int pos;
}MFILE;

/**************************************************************
 * FUNCTIONS 100% COMPATIBLE WITH USUAL F* FUNCTIONS - I HOPE *
 **************************************************************/
MFILE*		mfopen();
void		mfclose(MFILE *mf);
int			mfseek(MFILE *mf, int offset, int whence);
int 		mftell(MFILE *mf);
int 		mfeof(MFILE *mf);
int 		mfread(void *data, int times, int length, MFILE *mf);
int 		mfwrite(void *data, int times, int length, MFILE *mf);
int 		mfgetc(MFILE *mf);
int 		mfputc(unsigned char c, MFILE *mf);

/************************
 * ADDITIONAL FUNCTIONS *
 ************************/
int 		mfMFileToFile(MFILE *mf, FILE *f);
int 		mfFileToMFile(FILE *f, MFILE *mf);
const char*	mfGetData(MFILE *mf);
const char*	mfGetDataAt(MFILE *mf, int start);
int			mfSetLength(MFILE *mf, int length);
int 		mfGetLength(MFILE *mf);

4.3 ecgi-internal.h - not for the user!
you should not use this file - this is the part which is used internal, but "hidden" to the user - if you have any reason to include this file, i might have forgotten something.
Note: this file and the internal list of cgi elements might be changed later. The user interface of ecgi.h will not be changed. So you are compatible to following versions with ecgi.h - with ecgi-internal.h you might be not!

/***********************************************
 * THE STRUCTS/LIST WE STORE THE WHOLE SHIT IN *
 ***********************************************/

typedef struct _CgiValue{
	char *value;
	struct _CgiValue *next;
}CgiValue;

typedef struct _CgiElement {
	int type;
	char *name;
	char *ctyp;
	CgiValue *values;
	MFILE *mf;
	struct _CgiElement *next;
}CgiElement;

typedef struct _CGI{
	CgiElement *list;
	CgiElement *lastasked;
	CgiValue *lastret;
	CgiElement *lastvalasked;
	CgiElement *lastnameasked;
}Cgi;

/********************************
 * INTERNAL FUNCTION PROTOTYPES *
 ********************************/

// List Stuff
int listAddData(int type, const char *name, const char *value, const char *ctyp, MFILE *mf);
CgiElement *listGetByName(const char *name);
CgiElement *listAppendElement(int type, const char *name, const char *ctyp, MFILE *mf);
CgiValue *listAppendValue(CgiElement *where, const char *value);
int listHasValue(CgiElement *check, char *value);
void listFreeAll();
void listDump();	// for test usage only ... dumps all vals to stdout ...

// Init/Parse Stuff
int initGet();
int initPost();
int initMultiPart(const char *cont_type);
int parseMultiPart(char *boundary);
int parseMultiHead(char **name, char **fname, char **ctyp);
int parseQueryString(const char *str, int length); // str==NULL - read from stdin

// Misc Help Functions
int miscStringDecode(char *s);
int miscFReadLn(FILE *f, MFILE *mf);
int miscStringToUInt(const char *str, unsigned int *res);
char *miscStringDelCrLf(char *str);

/**********************
 * OTHER USELESS SHIT *
 **********************/

/* external vars - here for real */
int cgi_errno=0;
/* global vars */
Cgi *c=NULL;
int maxfilesize=-1;
int maxsize=-1;
int init_called=false;
int init_complete=false;

#define NUMERRS 25
static const char *errmsgs[NUMERRS] = {
  "Success",
  "Unknown request method",
  "Repeated initialization attempt",
  "Null query string",
  "Unknown content type",
  "Invalid content length",
  "Unexpected end of input stream",
  "Input stream read error",
  "Maximum entry name length exceeded",
  "Maximum entry value length exceeded",
  "Invalid URL-encoded data",
  "Maximum number of entries exceeded",
  "Memory allocation error",
  "Maximum memory limit exceeded",
  "Invalid boundary string",
  "Null file upload directory",
  "Pathname length limit exceeded",
  "Extremely long line encountered",
  "Missing boundary string",
  "Error opening file for writing",
  "Error writing to file",
  "Error closing file",
  "Error changing file permissions",
  "Missing initial boundary string",
  "Error parsing content disposition"
};

#define CGIERR_UREQM      1  /* Unknown request method */
#define CGIERR_REINIT     2  /* Repeated initialization attempt */
#define CGIERR_NULQSTR    3  /* Null query string */
#define CGIERR_UCONTT     4  /* Unknown content type */
#define CGIERR_ICONTLEN   5  /* Invalid content length */
#define CGIERR_UEOINP     6  /* Unexpected end of input stream */
#define CGIERR_INPREAD    7  /* Input stream read error */
#define CGIERR_MAXNAMEE   8  /* Maximum entry name length exceeded */
#define CGIERR_MAXVALE    9  /* Maximum entry value length exceeded */
#define CGIERR_IURLENC   10  /* Invalid URL-encoded data */
#define CGIERR_MAXENTRSE 11  /* Maximum number of entries exceeded */
#define CGIERR_MALLOC    12  /* Memory allocation error */
#define CGIERR_MAXMEME   13  /* Maximum memory limit exceeded */
#define CGIERR_IBSTR     14  /* Invalid boundary string */
#define CGIERR_NULUPLD   15  /* Null file upload directory */
#define CGIERR_PATHMAXE  16  /* Pathname length limit exceeded */
#define CGIERR_LONGLN    17  /* Extremely long line encountered */
#define CGIERR_MBSTR     18  /* Missing boundary string */
#define CGIERR_FOPEN     19  /* Error opening file for writing */
#define CGIERR_FWRITE    20  /* Error writing to file */
#define CGIERR_FCLOSE    21  /* Error closing file */
#define CGIERR_CHMOD     22  /* Error changing file permissions */
#define CGIERR_MBBSTR    23  /* Missing initial boundary string */
#define CGIERR_DISPPARS  24  /* Error parsing content disposition */



Appendix A - Demo Programms

These are two very simple, but working programms which should show the basic use of ecgilib.

A1 Simple-Demo

Demo1.html
	<html>
	<body><pre>
	<form action="demos.cgi" method="post">
	Name: <input type=text name="name">
	Password: <input type=password name="passwd">
	<input type=submit>
	</form>
	</html>

Demo1.c
#include <stdio.h>
#include <ecgi.h>

int main()
{
	cgiInit();

	printf("Content-Type: text/html\n\n");

	printf("Your name: %s\n", cgiParam("name"));
	printf("Your password: %s\n", cgiParam("passwd"));
	
	cgiDone();
	
	return(0);
}

Thats it!

A2 Multi Form Demo / All Data access Demo / Template Demo:

html/enter.h

const char htmlEnter[]="
<html><body><pre>
<form script=\"%s\">
<input type=hidden name=action value=%d>
Your Name: <input type=text name=name>
Your Password: <input type=text name=passwd>
<input type=submit>
</form>
</body></html>
";

html/pageTwo.h

const char htmlPageTwo[]="
<html><body><pre>
<form script=\"%s\">
<input type=hidden name=action value=%d>
<input type=hidden name=\"name\" value=\"%s\">
<input type=hidden name=\"passwd\" value=\"%s\">
Hello %s!
Please Select persons, you wanna kill: <select name=\"to kill\" multiple>
<option>Wife / Girlfriend</option>
<option>Mum and Dad</option>
<option>KILL ALL HUMANS</option>
</select>
Please Enter the amount of Bullets for each person: <input type=text name=bulcount>
<input type=submit value=\"kill em\">
</form>
</body></html>
";

html/pageThree.h

const char htmlPageThreeHead[]="
<html><head><title>Result of your inputs</title></head>
<body>
This is the data send from you:<p>
";

const char htmlPageThreeRowHead[]="
Name: %s <br> Values: <br>
";

const char htmlPageThreeRow[]="
%s <br>
";

const char htmlPageThreeRowFoot[]="
<hr width=90%%>
";

const char htmlPageThreeFoot[]="
<br>Your commands will be executed now!</body></html>";

demo2.c
#include <stdio.h>
#include <stdlib.h>
#include <ecgi.h>
#include "html/enter.h"
#include "html/pageTwo.h"
#include "html/pageThree.h"

#define ActEnter	0
#define ActPageTwo	1
#define ActPageThree	2

void mainEnter();
void mainPageTwo();
void mainPageThree();

const char *script;

int main()
{
	int action=0;
	const char *saction;
	
	cgi_init();
	script=getenv("SCRIPT_NAME");
	saction=cgiParam("action");
	if(saction!=NULL) action=atoi(saction);

	printf("Content-Type: text/html\n\n");
	
	switch(action){
		case ActPageTwo:	mainPageTwo(); break;
		case ActPageThree:	mainPageThree(); break;
		default:		mainEnter(); break;
	}
	
	cgiDone();
	
	return(0);
}

void mainEnter()
{
	printf(htmlEnter, script, ActPageTwo);
}

void mainPageTwo()
{
	printf(htmlPageTwo, script, ActPageThree, cgiParam("name"), cgiParam("passwd"), cgiParam("name"));
}

void mainPageThree()
{
	CgiPos *p=NULL;
	const char *val;
	cgiParam(NULL);

	// notice, no need to know any of the names of the fields from above

	printf(htmlPageThreeHead);
	
	while((p=cgiPosNext(p))!=NULL){
		printf(htmlPageThreeRowHead, cgiPosName(p));
		while((val=cgiPosParam(p))!=NULL)
			printf(htmlPageThreeRow, val);
		printf(htmlPageThreeRowFoot);
	}
	
	printf(htmlPageThreeFoot);
}
eCgiLib 0.6 Tutor

Print 02.12.2000 18:10		Seite 5