summaryrefslogtreecommitdiff
path: root/sys/src/cmd/urlencode.c
blob: 1d10a977f708c6d64cf16cea63214cbb46a4843b (plain)
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
#include <u.h>
#include <libc.h>
#include <bio.h>

Biobuf	bin;
Biobuf	bout;
int	dflag;

char	hex[] = "0123456789abcdef";
char	Hex[] = "0123456789ABCDEF";

int
hexdigit(int c)
{
	char *p;

	if(c > 0){
		if((p = strchr(Hex, c)) != 0)
			return p - Hex;
		if((p = strchr(hex, c)) != 0)
			return p - hex;
	}
	return -1;
}

void
usage(void)
{
	fprint(2, "Usage: %s [ -d ] [ file ]\n", argv0);
	exits("usage");
}

void
main(int argc, char *argv[])
{
	int c;

	ARGBEGIN {
	case 'd':
		dflag = 1;
		break;
	default:
		usage();
	} ARGEND;

	if(argc == 1){
		int fd;

		fd = open(*argv, OREAD);
		if(fd < 0)
			sysfatal("%r");
		if(fd != 0) dup(fd, 0);
	} else if(argc > 1)
		usage();

	Binit(&bin, 0, OREAD);
	Binit(&bout, 1, OWRITE);

	if(dflag){
		while((c = Bgetc(&bin)) >= 0){
			if(c == '%'){
				int c1, c2, x1, x2;

				if((c1 = Bgetc(&bin)) < 0)
					break;
				if((x1 = hexdigit(c1)) < 0){
					Bungetc(&bin);
					Bputc(&bout, c);
					continue;
				}
				if((c2 = Bgetc(&bin)) < 0)
					break;
				if((x2 = hexdigit(c2)) < 0){
					Bungetc(&bin);
					Bputc(&bout, c);
					Bputc(&bout, c1);
					continue;
				}
				c = x1<<4 | x2;
			} else if(c == '+')
				c = ' ';
			Bputc(&bout, c);
		}
	} else {
		while((c = Bgetc(&bin)) >= 0){
			if(c>0 && strchr("/$-_@.!*'(),", c)
			|| 'a'<=c && c<='z'
			|| 'A'<=c && c<='Z'
			|| '0'<=c && c<='9')
				Bputc(&bout, c);
			else if(c == ' ')
				Bputc(&bout, '+');
			else {
				Bputc(&bout, '%');
				Bputc(&bout, Hex[c>>4]);
				Bputc(&bout, Hex[c&15]);
			}
		}
	}

	Bflush(&bout);
	exits(0);
}