Skip to content

Commit 49b6048

Browse files
authored
Merge pull request #16 from sksat/master
cat実装
2 parents a3646ce + 02b6515 commit 49b6048

File tree

1 file changed

+369
-0
lines changed

1 file changed

+369
-0
lines changed

cat/sksat-cat.c

Lines changed: 369 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,369 @@
1+
// compile: $(CC) sksat-cat.c -o sksat-cat -nostdlib -fno-builtin -fno-stack-protector
2+
3+
#define NULL 0x00
4+
5+
// std types
6+
typedef _Bool bool;
7+
#define true 1
8+
#define false 0
9+
// 64bit
10+
#define __SIZE_TYPE__ long unsigned int
11+
typedef long __kernel_ssize_t;
12+
13+
typedef __SIZE_TYPE__ size_t;
14+
typedef __kernel_ssize_t ssize_t;
15+
16+
// my stdlib
17+
18+
// system call
19+
20+
#define TO_STRING(str) #str
21+
#define STR(val) TO_STRING(val)
22+
23+
#define NUM_READ 0
24+
#define NUM_WRITE 1
25+
#define NUM_OPEN 2
26+
#define NUM_CLOSE 3
27+
#define NUM_EXIT 60
28+
#define NUM_OPENAT 257
29+
30+
#define AT_FDCWD -100
31+
32+
ssize_t sys_read(unsigned int fd, char *buf, size_t count);
33+
void sys_write(unsigned int fd, const char *buf, size_t count);
34+
int sys_open(const char *fname, int flags, int mode);
35+
int sys_close(unsigned int fd);
36+
void sys_exit(int status);
37+
38+
// file
39+
#define stdin 0
40+
#define stdout 1
41+
#define stderr 2
42+
43+
#define O_RDONLY 0x0000
44+
#define O_WRONLY 0x0001
45+
#define O_RDWR 0x0002
46+
#define O_ACCMODE 0x0003
47+
48+
// funcs
49+
void* memset(void *buf, int ch, size_t n);
50+
size_t strlen(const char *str);
51+
int strcmp(const char *s1, const char *s2);
52+
void fputs(int fd, const char *str);
53+
void putchar(const int c);
54+
void puts(const char *str);
55+
char* puts_printing(const char *str);
56+
void puti(const int val);
57+
58+
59+
#define BUF_SIZE 256
60+
61+
char output_opt; // do not initialize here!!!
62+
#define OPT_END 0b00000001
63+
#define OPT_NONBLANK 0b00000010
64+
#define OPT_NUMBER 0b00000100
65+
#define OPT_SQUEEZE 0b00001000
66+
#define OPT_TAB 0b00010000
67+
#define OPT_NOPRINT 0b00100000
68+
69+
int main(int argc, char **argv);
70+
size_t check_cmdline(const int argc, char **argv);
71+
void check_option(const char *opt);
72+
void cat_loop(int fd);
73+
void print_with_opt(const char *buf);
74+
void print_newline();
75+
void error(const char *msg);
76+
77+
// entry point
78+
asm(
79+
".global _start;"
80+
"_start:\n"
81+
" xorl %ebp, %ebp;"
82+
" movq 0(%rsp), %rdi;"
83+
" lea 8(%rsp), %rsi;"
84+
" call main");
85+
86+
int main(int argc, char **argv){
87+
char buf[BUF_SIZE];
88+
89+
if(check_cmdline(argc, argv) == 0){
90+
cat_loop(stdin);
91+
sys_exit(0);
92+
}
93+
94+
for(int n=1;n<argc;n++){
95+
int fd;
96+
size_t len = strlen(argv[n]);
97+
98+
if(len == 0) continue;
99+
100+
if(argv[n][0] == '-' && len == 1)
101+
fd = stdin;
102+
else
103+
fd = sys_open(argv[n], O_RDONLY, 0);
104+
if(fd < 0)
105+
error("cannot open file.\n");
106+
cat_loop(fd);
107+
sys_close(fd);
108+
}
109+
110+
sys_exit(0);
111+
}
112+
113+
size_t check_cmdline(const int argc, char **argv){
114+
size_t fnum = 0;
115+
output_opt = 0x00;
116+
for(int n=1;n<argc;n++){
117+
if(strlen(argv[n]) == 0) continue;
118+
if(argv[n][0] != '-'){
119+
fnum++;
120+
continue;
121+
}
122+
if(argv[n][1] == '\0'){ // "-" stdin
123+
fnum++;
124+
continue;
125+
}
126+
check_option(argv[n]);
127+
memset(argv[n], '\0', strlen(argv[n]));
128+
}
129+
return fnum;
130+
}
131+
132+
void check_option(const char *opt){
133+
bool flg_exit = false;
134+
size_t h_num = 1;
135+
opt++;
136+
if(*opt == '-'){ // --***
137+
h_num++;
138+
opt++;
139+
}
140+
141+
if((h_num==1 && strcmp(opt, "E")==0) |
142+
(h_num==2 && strcmp(opt, "show-ends")==0))
143+
output_opt |= OPT_END;
144+
else if((h_num==1 && strcmp(opt, "n")==0) |
145+
(h_num==2 && strcmp(opt, "number")==0))
146+
//error("not implemented option.\n");
147+
output_opt |= OPT_NUMBER;
148+
else if((h_num==1 && strcmp(opt, "s")==0) |
149+
(h_num==2 && strcmp(opt, "squeeze-blank")==0))
150+
output_opt |= OPT_SQUEEZE;
151+
else if((h_num==1 && strcmp(opt, "T")==0) |
152+
(h_num==2 && strcmp(opt, "show-tabs")==0))
153+
output_opt |= OPT_TAB;
154+
else if(h_num == 2 && strcmp(opt, "help") == 0){
155+
flg_exit = true;
156+
puts("Usage: ./sksat-cat [OPTION]... [FILE]...\n"
157+
"Concatenate FILE(s) to standard output.\n\n"
158+
"With no FILE, or when FILE is -, read standard input.\n\n"
159+
" -E, --show-ends display $ at end of each line\n"
160+
" -n, --number number all output lines\n"
161+
" -s, --squeeze-blank suppress repeated empty output lines\n"
162+
" -T, --show-tabs display TAB characters as ^I\n"
163+
" --help display this help and exit\n"
164+
" --version output version information and exit\n"
165+
"Examples:\n"
166+
" ./sksat-cat f - g Output f's contents, then standard input, then g's contents.\n"
167+
" ./sksat-cat Copy standard input to standard output.\n"
168+
"\n");
169+
}else if(h_num == 2 && strcmp(opt, "version") == 0){
170+
flg_exit = true;
171+
puts("sksat-cat 0.1\n"
172+
"Copyright (C) 2019 sksat\n"
173+
"License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.\n"
174+
"This is free software: you are free to change and redistribute it.\n"
175+
"There is NO WARRANTY, to the extent permitted by law.\n\n"
176+
"Written by sksat <sksat@sfc.wide.ad.jp>\n");
177+
}else{
178+
flg_exit = true;
179+
puts("sksat-cat: unrecognized option '");
180+
for(int i=0;i<h_num;i++) puts("-");
181+
puts(opt);
182+
puts("\'\n");
183+
puts("Try \'sksat-cat --help\' for more information.\n");
184+
}
185+
186+
if(flg_exit)
187+
sys_exit(0);
188+
}
189+
190+
void cat_loop(int fd){
191+
char buf[BUF_SIZE];
192+
193+
if(output_opt != 0x00)
194+
print_newline();
195+
196+
for(;;){
197+
memset(buf, '\0', BUF_SIZE);
198+
if(sys_read(fd, buf, BUF_SIZE-1) == 0)
199+
break;
200+
if(output_opt != 0x00)
201+
print_with_opt(buf);
202+
else
203+
puts(buf);
204+
}
205+
}
206+
207+
void print_with_opt(const char *buf){
208+
static bool last_newline = false;
209+
char *s = (char*)buf;
210+
211+
if(last_newline){
212+
print_newline();
213+
last_newline = true;
214+
}
215+
216+
for(;;){
217+
s = puts_printing(s);
218+
if(*s == '\0'){
219+
if(*(s-1) == '\n') last_newline = true;
220+
break;
221+
}
222+
223+
// non printing
224+
switch(*s){
225+
case '\n':
226+
if(output_opt & OPT_SQUEEZE){
227+
char *tmp = s+1;
228+
for(;;){
229+
if(*tmp!='\n') break;
230+
tmp++;
231+
}
232+
233+
if((tmp-s) > 1)
234+
print_newline();
235+
s = tmp-1;
236+
}
237+
print_newline();
238+
break;
239+
case '\t':
240+
if(output_opt & OPT_TAB)
241+
puts("^I");
242+
else
243+
putchar('\t');
244+
break;
245+
}
246+
s++;
247+
}
248+
}
249+
250+
void print_newline(){
251+
static int line = 1;
252+
char *newline_str = "\n";
253+
254+
if(output_opt & OPT_END)
255+
newline_str = "$\n";
256+
257+
if(line != 1)
258+
puts(newline_str);
259+
260+
if(output_opt & OPT_NUMBER){
261+
puts(" ");
262+
puti(line);
263+
puts(" ");
264+
}
265+
266+
line++;
267+
}
268+
269+
void error(const char *msg){
270+
puts(msg);
271+
sys_exit(-1);
272+
}
273+
274+
// library funcs impl
275+
276+
void* memset(void *buf, int ch, size_t n){
277+
int i;
278+
for(i=0;i<n;i++){
279+
((char*)buf)[i] = ch;
280+
}
281+
return buf;
282+
}
283+
284+
size_t strlen(const char *str){
285+
size_t len;
286+
for(len=0;;len++){
287+
if(str[len] == '\0')
288+
break;
289+
}
290+
return len;
291+
}
292+
293+
int strcmp(const char *s1, const char *s2){
294+
size_t l1, l2, len;
295+
l1 = strlen(s1);
296+
l2 = strlen(s2);
297+
len = (l1<l2 ? l1 : l2);
298+
for(int n=0;n<len;n++){
299+
if(s1[n] != s2[n]) return 1;
300+
}
301+
return 0;
302+
}
303+
304+
void fputs(int fd, const char *str){
305+
sys_write(fd, str, strlen(str));
306+
return;
307+
}
308+
309+
void putchar(const int c){
310+
sys_write(stdout, (const char*)&c, 1);
311+
}
312+
313+
void puts(const char *str){
314+
fputs(stdout, str);
315+
}
316+
317+
char* puts_printing(const char *str){
318+
size_t n=0;
319+
320+
for(;;n++){
321+
const char c = str[n];
322+
if(c == '\0' || c == '\n' || c == '\t') break;
323+
}
324+
325+
sys_write(stdout, str, n);
326+
return (char*)str+n;
327+
}
328+
329+
void puti(const int val){
330+
if(!val) return;
331+
int i= 0;
332+
int l = val;
333+
while(l/=10) i++;
334+
335+
puti(val/10);
336+
putchar('0'+(val%10));
337+
}
338+
339+
// system call wrapper impl
340+
341+
ssize_t sys_read(unsigned int fd, char *buf, size_t count){
342+
asm volatile (
343+
"mov $" STR(NUM_READ) ", %rax;"
344+
"syscall");
345+
}
346+
347+
void sys_write(unsigned int fd, const char *buf, size_t count){
348+
asm volatile (
349+
"mov $" STR(NUM_WRITE) ", %rax;"
350+
"syscall");
351+
}
352+
353+
int sys_open(const char *fname, int flags, int mode){
354+
asm volatile (
355+
"mov $" STR(NUM_OPEN) ", %rax;"
356+
"syscall");
357+
}
358+
359+
int sys_close(unsigned int fd){
360+
asm volatile (
361+
"mov $" STR(NUM_CLOSE) ", %rax;"
362+
"syscall");
363+
}
364+
365+
void sys_exit(int status){
366+
asm volatile (
367+
"mov $" STR(NUM_EXIT) ", %rax;"
368+
"syscall");
369+
}

0 commit comments

Comments
 (0)