Skip to content

Commit e09aaee

Browse files
committed
Add (untested, but it compiles OK) scorpionlib.
1 parent 2eb28c6 commit e09aaee

File tree

3 files changed

+354
-0
lines changed

3 files changed

+354
-0
lines changed

scorpionlib.c

+223
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
#if 0
2+
gcc -s -O2 -c scorpionlib.c
3+
exit
4+
#endif
5+
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
#include <string.h>
9+
#include "scorpionlib.h"
10+
11+
void scorpionlib_ask(const char*in,char*out,int len,const char*prompt) {
12+
if(scorpionlib_query(in,out,len)) return;
13+
printf("10 %s\r\n",prompt);
14+
exit(0);
15+
}
16+
17+
void scorpionlib_bad_request(void) {
18+
puts("59 Bad request\r");
19+
exit(0);
20+
}
21+
22+
void scorpionlib_begin(const char*type,const char*version) {
23+
printf("20 ? %s%s%s\r\n",type,version?" ":"",version?:"");
24+
}
25+
26+
void scorpionlib_begin_size(char kind,unsigned long size,const char*type,const char*version) {
27+
printf("2%c %lu %s%s%s\r\n",kind,size,type,version?" ":"",version?:"");
28+
}
29+
30+
void scorpionlib_error(const char*text) {
31+
printf("50 %s\r\n",text?:"Permanent error");
32+
exit(0);
33+
}
34+
35+
void scorpionlib_forbid(void) {
36+
puts("54 Forbidden\r");
37+
exit(0);
38+
}
39+
40+
int scorpionlib_fputc_pc(int code,FILE*file) {
41+
code&=255;
42+
if(!code) return -1;
43+
if(code<0x20) fputc(0x10,file),code+=0x40;
44+
return fputc(code,file);
45+
}
46+
47+
int scorpionlib_fputc_tron8(unsigned int*state,unsigned long code,FILE*file) {
48+
unsigned int i;
49+
if(i=code>>16) {
50+
if(!state || (*state&0xFFFF)!=i) {
51+
if(state) *state=i;
52+
fputc(0xFE,file);
53+
while(i--) fputc(0xFE,file);
54+
}
55+
fputc(code>>8,file);
56+
}
57+
return fputc(code,file);
58+
}
59+
60+
void scorpionlib_fputs_pc(const char*text,FILE*file) {
61+
const unsigned char*t=(const unsigned char*)text;
62+
while(*t) {
63+
if(*t>=0x20) {
64+
fputc(*t++,file);
65+
} else {
66+
fputc(0x10,file);
67+
fputc(*t++|0x40,file);
68+
}
69+
}
70+
}
71+
72+
int scorpionlib_fputs_tron8(unsigned int*state,const char*text,FILE*file) {
73+
if(state) {
74+
const char*x;
75+
unsigned int i=0;
76+
while(i<(*state>>16) && text[i]==(char)0xFE) i++;
77+
if(i==(*state>>16) && text[i]==(char)(*state&255)) text+=i+1;
78+
if((x=strrchr(text,0xFE)) && x[1]) {
79+
*state=x[1]&255;
80+
while(x>text && x[-1]==(char)0xFE) x--,*state+=0x100;
81+
}
82+
}
83+
return fputs(text,file);
84+
}
85+
86+
void scorpionlib_not_found(void) {
87+
puts("51 File not found\r");
88+
exit(0);
89+
}
90+
91+
void scorpionlib_print_block(int type,const char*adata,int alen,const char*bdata,int blen) {
92+
scorpionlib_write_block(stdout,type,adata,alen,bdata,blen);
93+
}
94+
95+
int scorpionlib_query(const char*in,char*out,int len) {
96+
int n=0;
97+
int c;
98+
for(;;) {
99+
if(*in=='#' || !*in) return 0;
100+
if(*in=='?') {
101+
in++;
102+
while(n<len) {
103+
if(*in=='#' || !*in) break;
104+
if(*in=='+') {
105+
out[n++]=' ';
106+
in++;
107+
} else if(*in!='%') {
108+
out[n++]=*in++;
109+
} else {
110+
in++;
111+
if(*in>='0' && *in<='9') c=*in++-'0';
112+
else if(*in>='A' && *in<='F') c=*in++-'A'+10;
113+
else if(*in>='a' && *in<='f') c=*in++-'a'+10;
114+
else scorpionlib_bad_request();
115+
c<<=4;
116+
if(*in>='0' && *in<='9') c|=*in++-'0';
117+
else if(*in>='A' && *in<='F') c|=*in++-'A'+10;
118+
else if(*in>='a' && *in<='f') c|=*in++-'a'+10;
119+
else scorpionlib_bad_request();
120+
out[n++]=c;
121+
}
122+
}
123+
return 1;
124+
}
125+
in++;
126+
}
127+
}
128+
129+
int scorpionlib_receiver(const char*req,unsigned long*start,unsigned long*end,char*kind) {
130+
const char*p=req+1;
131+
if(*req!='R') return 0;
132+
if(*p!=' ') {
133+
if(!start || !end) return 0;
134+
*kind='1';
135+
*start=0;
136+
while(*p>='0' && *p<='9') *start=*start*10+*p++-'0';
137+
if(*p++!='-') return 0;
138+
if(*p==' ') return 1;
139+
*end=0;
140+
while(*p>='0' && *p<='9') *end=*end*10+*p++-'0';
141+
} else {
142+
*kind='0';
143+
if(start) *start=0;
144+
}
145+
return 1;
146+
}
147+
148+
void scorpionlib_redirect(char perm,const char*target) {
149+
printf("3%c %s\r\n",perm?'1':'0',target);
150+
exit(0);
151+
}
152+
153+
int scorpionlib_user_info(const char*req,char*user,int userlen,char*pass,int passlen) {
154+
unsigned int i,c;
155+
req=strchr(req,' ');
156+
if(!req) return 0;
157+
while(*req!=':') req++;
158+
while(*req=='/') req++;
159+
for(i=0;;) {
160+
if(*req=='@') {
161+
req++;
162+
user[i]=0;
163+
*pass=0;
164+
return 1;
165+
} else if(*req==':') {
166+
req++;
167+
user[i]=0;
168+
break;
169+
} else if(*req=='%') {
170+
if(i==userlen) return 0;
171+
req++;
172+
if(*req>='0' && *req<='9') c=*req++-'0';
173+
else if(*req>='A' && *req<='F') c=*req++-'A'+10;
174+
else if(*req>='a' && *req<='f') c=*req++-'a'+10;
175+
else return 0;
176+
c<<=4;
177+
if(*req>='0' && *req<='9') c|=*req++-'0';
178+
else if(*req>='A' && *req<='F') c|=*req++-'A'+10;
179+
else if(*req>='a' && *req<='f') c|=*req++-'a'+10;
180+
else return 0;
181+
user[i++]=c;
182+
} else if(*req=='/' || !*req) {
183+
return 0;
184+
} else {
185+
if(i==userlen) return 0;
186+
user[i++]=*req++;
187+
}
188+
}
189+
for(i=0;;) {
190+
if(*req=='@') {
191+
req++;
192+
pass[i]=0;
193+
return 2;
194+
} else if(*req=='%') {
195+
if(i==passlen) return 0;
196+
req++;
197+
if(*req>='0' && *req<='9') c=*req++-'0';
198+
else if(*req>='A' && *req<='F') c=*req++-'A'+10;
199+
else if(*req>='a' && *req<='f') c=*req++-'a'+10;
200+
else return 0;
201+
c<<=4;
202+
if(*req>='0' && *req<='9') c|=*req++-'0';
203+
else if(*req>='A' && *req<='F') c|=*req++-'A'+10;
204+
else if(*req>='a' && *req<='f') c|=*req++-'a'+10;
205+
else return 0;
206+
pass[i++]=c;
207+
} else if(*req=='/' || !*req) {
208+
return 0;
209+
} else {
210+
if(i==passlen) return 0;
211+
pass[i++]=*req++;
212+
}
213+
}
214+
}
215+
216+
void scorpionlib_write_block(FILE*fp,int type,const char*adata,int alen,const char*bdata,int blen) {
217+
fputc(type,fp);
218+
fputc(alen>>8,fp); fputc(alen,fp);
219+
fwrite(adata,1,alen,fp);
220+
fputc(blen>>16,fp); fputc(blen>>8,fp); fputc(blen,fp);
221+
fwrite(bdata,1,blen,fp);
222+
}
223+

scorpionlib.doc

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
2+
void scorpionlib_ask(const char*in,char*out,int len,const char*prompt)
3+
If there is no query string, then it asks the user (with the given prompt
4+
text) and terminates. If there is a query string, then it is the same as
5+
scorpionlib_query.
6+
7+
void scorpionlib_bad_request(void);
8+
Send a bad request error and terminate.
9+
10+
void scorpionlib_begin(const char*type,const char*version);
11+
Send a header for a file of an unknown size, where "type" is the MIME or
12+
ULFI type, and "version" is the version string (which can be null).
13+
14+
void scorpionlib_begin_size(char kind,unsigned long size,const char*type,const char*version);
15+
Like scorpionlib_begin but the size is explicitly known, and the "kind"
16+
should be the kind that was written by scorpionlib_receiver ('0' if it
17+
is not a range request, or '1' if it is).
18+
19+
void scorpionlib_error(const char*text);
20+
Send a custom permanent error message (it automatically adds "50")
21+
and then it will immediately terminate.
22+
23+
void scorpionlib_forbid(void);
24+
Send a forbidden error and terminate.
25+
26+
int scorpionlib_fputc_pc(int code,FILE*file);
27+
Write a single byte character; if it is in the controls range then it
28+
will send the appropriate code (according to the Scorpion file format)
29+
to treat it as a graphic character instead. This should be used only
30+
with the PC character set.
31+
32+
int scorpionlib_fputc_tron8(unsigned int*state,unsigned long code,FILE*file);
33+
Write a single TRON character, encoding it as TRON-8. If state is null,
34+
then it always emits a plane shift if it is not a control code. If state
35+
is not null, then it reads from it and omits the plane shift if it is
36+
already in the correct state, or does emit the plane shift and also
37+
updates the state, if it needs to change the state. (The initial state
38+
should normally be zero.)
39+
40+
void scorpionlib_fputs_pc(const char*text,FILE*file);
41+
Send a character string with the PC character set, replacing all codes
42+
in the control range with the control code to display them as graphic
43+
characters (according to the Scorpion file format).
44+
45+
int scorpionlib_fputs_tron8(unsigned int*state,const char*text,FILE*file);
46+
Write a TRON-8 string. If the state is null then it is the same as fputs.
47+
If state is not null, then it will omit any prefix that selects the shift
48+
state if that is already the shift state, and will update the state with
49+
the final shift state of the string.
50+
51+
void scorpionlib_not_found(void);
52+
Send a file not found error and terminate.
53+
54+
void scorpionlib_print_block(int type,const char*adata,int alen,const char*bdata,int blen);
55+
Writes a block in the Scorpion file format to stdout. The type is the
56+
bitwise OR of the constant for the block type and the character encoding.
57+
The adata and alen are the attribute data and length, and the bdata and
58+
blen are the body data and length.
59+
60+
int scorpionlib_query(const char*in,char*out,int len);
61+
The in argument should be argv[2]. If it has no query string, then it
62+
returns zero. If there is a query string, then it is decoded and written
63+
to out, up to the maximum length, and returns 1. If there is any invalid
64+
percent encoding then it calls scorpionlib_bad_request(). (The maximum
65+
length does not include the null terminator; the buffer must be big
66+
enough to include it.)
67+
68+
int scorpionlib_receiver(const char*req,unsigned long*start,unsigned long*end,char*kind);
69+
The first argument should be argv[1]. It checks that it is a receive
70+
request. If not, it returns 0. Otherwise, it will check for a range
71+
request, write to start and end if they are not null, and return 1.
72+
The end is left unchanged if it is not a range request or if no
73+
ending range has been specified. It returns 0 if it is a range request
74+
but start and/or end are null. The kind will be set to '0' if it is not
75+
a range request or to '1' if it is.
76+
77+
void scorpionlib_redirect(char perm,const char*target);
78+
Sends a redirect and terminates. The first argument is zero for a
79+
temporary redirect or nonzero for permanent, and the second argument
80+
is the target URL.
81+
82+
int scorpionlib_user_info(const char*req,char*user,int userlen,char*pass,int passlen);
83+
The first argument should be argv[1]. The user and pass must be not null,
84+
and userlen and passlen are the maximum lengths (the actual size of the
85+
buffers must be one more, to add the null character). It returns 1 if a
86+
user name has been provided but no password, 2 if both a user name and a
87+
password have been provided or 0 if neither has been provided or if the
88+
provided user name and/or password are too long. The user name and
89+
password are written into the provided buffers.
90+
91+
void scorpionlib_write_block(FILE*fp,int type,const char*adata,int alen,const char*bdata,int blen);
92+
Like scorpionlib_print_block but writes to a file instead of stdout.
93+

scorpionlib.h

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
2+
#define SCORPIONLIB_CHARSET_TRON8 0x00
3+
#define SCORPIONLIB_CHARSET_TRON8_LTR 0x00
4+
#define SCORPIONLIB_CHARSET_PC 0x10
5+
#define SCORPIONLIB_CHARSET_TRON8_RTL 0x80
6+
7+
#define SCORPIONLIB_BLOCK_NORMAL 0x00
8+
#define SCORPIONLIB_BLOCK_HEAD1 0x01
9+
#define SCORPIONLIB_BLOCK_HEAD2 0x02
10+
#define SCORPIONLIB_BLOCK_HEAD3 0x03
11+
#define SCORPIONLIB_BLOCK_HEAD4 0x04
12+
#define SCORPIONLIB_BLOCK_HEAD5 0x05
13+
#define SCORPIONLIB_BLOCK_HEAD6 0x06
14+
#define SCORPIONLIB_BLOCK_HYPERLINK 0x08
15+
#define SCORPIONLIB_BLOCK_HYPERLINK_INPUT 0x09
16+
#define SCORPIONLIB_BLOCK_HYPERLINK_INTERACTIVE 0x0A
17+
#define SCORPIONLIB_BLOCK_BLOCKQUOTE 0x0C
18+
#define SCORPIONLIB_BLOCK_PREFORMATTED 0x0D
19+
20+
void scorpionlib_ask(const char*in,char*out,int len,const char*prompt);
21+
void scorpionlib_bad_request(void);
22+
void scorpionlib_begin(const char*type,const char*version);
23+
void scorpionlib_begin_size(char kind,unsigned long size,const char*type,const char*version);
24+
void scorpionlib_error(const char*text);
25+
void scorpionlib_forbid(void);
26+
int scorpionlib_fputc_pc(int code,FILE*file);
27+
int scorpionlib_fputc_tron8(unsigned int*state,unsigned long code,FILE*file);
28+
void scorpionlib_fputs_pc(const char*text,FILE*file);
29+
int scorpionlib_fputs_tron8(unsigned int*state,const char*text,FILE*file);
30+
void scorpionlib_not_found(void);
31+
void scorpionlib_print_block(int type,const char*adata,int alen,const char*bdata,int blen);
32+
int scorpionlib_query(const char*in,char*out,int len);
33+
int scorpionlib_receiver(const char*req,unsigned long*start,unsigned long*end,char*kind);
34+
void scorpionlib_redirect(char perm,const char*target);
35+
int scorpionlib_user_info(const char*req,char*user,int userlen,char*pass,int passlen);
36+
void scorpionlib_write_block(FILE*fp,int type,const char*adata,int alen,const char*bdata,int blen);
37+
38+
// cat scorpionlib.c | sed -rn '/^[^ ]/s/ \{$/;/p'

0 commit comments

Comments
 (0)