1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2012-11-23 Yihui The first version
9 * 2013-11-24 aozima fixed _sys_read()/_sys_write() issues.
10 * 2014-08-03 bernard If using msh, use system() implementation
11 * in msh.
12 */
13
14 #include <string.h>
15 #include <rt_sys.h>
16
17 #include "rtthread.h"
18 #include "libc.h"
19
20 #ifdef RT_USING_DFS
21 #include "dfs_posix.h"
22 #endif
23
24 #ifdef __CLANG_ARM
25 __asm(".global __use_no_semihosting\n\t");
26 #else
27 #pragma import(__use_no_semihosting_swi)
28 #endif
29
30 /* Standard IO device handles. */
31 #define STDIN 0
32 #define STDOUT 1
33 #define STDERR 2
34
35 /* Standard IO device name defines. */
36 const char __stdin_name[] = "STDIN";
37 const char __stdout_name[] = "STDOUT";
38 const char __stderr_name[] = "STDERR";
39
40 /**
41 * required by fopen() and freopen().
42 *
43 * @param name - file name with path.
44 * @param openmode - a bitmap hose bits mostly correspond directly to
45 * the ISO mode specification.
46 * @return -1 if an error occurs.
47 */
_sys_open(const char * name,int openmode)48 FILEHANDLE _sys_open(const char *name, int openmode)
49 {
50 #ifdef RT_USING_DFS
51 int fd;
52 int mode = O_RDONLY;
53 #endif
54
55 /* Register standard Input Output devices. */
56 if (strcmp(name, __stdin_name) == 0)
57 return (STDIN);
58 if (strcmp(name, __stdout_name) == 0)
59 return (STDOUT);
60 if (strcmp(name, __stderr_name) == 0)
61 return (STDERR);
62
63 #ifndef RT_USING_DFS
64 return -1;
65 #else
66 /* Correct openmode from fopen to open */
67 if (openmode & OPEN_PLUS)
68 {
69 if (openmode & OPEN_W)
70 {
71 mode |= (O_RDWR | O_TRUNC | O_CREAT);
72 }
73 else if (openmode & OPEN_A)
74 {
75 mode |= (O_RDWR | O_APPEND | O_CREAT);
76 }
77 else
78 mode |= O_RDWR;
79 }
80 else
81 {
82 if (openmode & OPEN_W)
83 {
84 mode |= (O_WRONLY | O_TRUNC | O_CREAT);
85 }
86 else if (openmode & OPEN_A)
87 {
88 mode |= (O_WRONLY | O_APPEND | O_CREAT);
89 }
90 }
91
92 fd = open(name, mode, 0);
93 if (fd < 0)
94 return -1;
95 else
96 return fd;
97 #endif
98 }
99
_sys_close(FILEHANDLE fh)100 int _sys_close(FILEHANDLE fh)
101 {
102 #ifndef RT_USING_DFS
103 return 0;
104 #else
105 if (fh <= STDERR) return 0;
106
107 return close(fh);
108 #endif
109 }
110
111 /*
112 * Read from a file. Can return:
113 * - zero if the read was completely successful
114 * - the number of bytes _not_ read, if the read was partially successful
115 * - the number of bytes not read, plus the top bit set (0x80000000), if
116 * the read was partially successful due to end of file
117 * - -1 if some error other than EOF occurred
118 *
119 * It is also legal to signal EOF by returning no data but
120 * signalling no error (i.e. the top-bit-set mechanism need never
121 * be used).
122 *
123 * So if (for example) the user is trying to read 8 bytes at a time
124 * from a file in which only 5 remain, this routine can do three
125 * equally valid things:
126 *
127 * - it can return 0x80000003 (3 bytes not read due to EOF)
128 * - OR it can return 3 (3 bytes not read), and then return
129 * 0x80000008 (8 bytes not read due to EOF) on the next attempt
130 * - OR it can return 3 (3 bytes not read), and then return
131 * 8 (8 bytes not read, meaning 0 read, meaning EOF) on the next
132 * attempt
133 *
134 * `mode' exists for historical reasons and must be ignored.
135 */
_sys_read(FILEHANDLE fh,unsigned char * buf,unsigned len,int mode)136 int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode)
137 {
138 #ifdef RT_USING_DFS
139 int size;
140 #endif
141
142 if (fh == STDIN)
143 {
144 #ifdef RT_USING_POSIX
145 size = libc_stdio_read(buf, len);
146 return len - size;
147 #else
148 /* no stdin */
149 return -1;
150 #endif
151 }
152
153 if ((fh == STDOUT) || (fh == STDERR))
154 return -1;
155
156 #ifndef RT_USING_DFS
157 return 0;
158 #else
159 size = read(fh, buf, len);
160 if (size >= 0)
161 return len - size;
162 else
163 return -1;
164 #endif
165 }
166
167 /*
168 * Write to a file. Returns 0 on success, negative on error, and
169 * the number of characters _not_ written on partial success.
170 * `mode' exists for historical reasons and must be ignored.
171 */
_sys_write(FILEHANDLE fh,const unsigned char * buf,unsigned len,int mode)172 int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode)
173 {
174 #ifdef RT_USING_DFS
175 int size;
176 #endif
177
178 if ((fh == STDOUT) || (fh == STDERR))
179 {
180 #if !defined(RT_USING_CONSOLE) || !defined(RT_USING_DEVICE)
181 return 0;
182 #else
183 #ifdef RT_USING_POSIX
184 size = libc_stdio_write(buf, len);
185 return len - size;
186 #else
187 if (rt_console_get_device())
188 {
189 rt_device_write(rt_console_get_device(), -1, buf, len);
190 return 0;
191 }
192
193 return -1;
194 #endif
195 #endif
196 }
197
198 if (fh == STDIN) return -1;
199
200 #ifndef RT_USING_DFS
201 return 0;
202 #else
203 size = write(fh, buf, len);
204 if (size >= 0)
205 return len - size;
206 else
207 return -1;
208 #endif
209 }
210
211 /*
212 * Move the file position to a given offset from the file start.
213 * Returns >=0 on success, <0 on failure.
214 */
_sys_seek(FILEHANDLE fh,long pos)215 int _sys_seek(FILEHANDLE fh, long pos)
216 {
217 if (fh < STDERR)
218 return -1;
219
220 #ifndef RT_USING_DFS
221 return -1;
222 #else
223
224 /* position is relative to the start of file fh */
225 return lseek(fh, pos, 0);
226 #endif
227 }
228
229 /**
230 * used by tmpnam() or tmpfile()
231 */
_sys_tmpnam(char * name,int fileno,unsigned maxlength)232 int _sys_tmpnam(char *name, int fileno, unsigned maxlength)
233 {
234 return -1;
235 }
236
_sys_command_string(char * cmd,int len)237 char *_sys_command_string(char *cmd, int len)
238 {
239 /* no support */
240 return RT_NULL;
241 }
242
243 /* This function writes a character to the console. */
_ttywrch(int ch)244 void _ttywrch(int ch)
245 {
246 #ifdef RT_USING_CONSOLE
247 char c;
248
249 c = (char)ch;
250 rt_kprintf(&c);
251 #endif
252 }
253
_sys_exit(int return_code)254 void _sys_exit(int return_code)
255 {
256 /* TODO: perhaps exit the thread which is invoking this function */
257 while (1);
258 }
259
260 /**
261 * return current length of file.
262 *
263 * @param fh - file handle
264 * @return file length, or -1 on failed
265 */
_sys_flen(FILEHANDLE fh)266 long _sys_flen(FILEHANDLE fh)
267 {
268 struct stat stat;
269
270 if (fh < STDERR)
271 return -1;
272
273 #ifndef RT_USING_DFS
274 return -1;
275 #else
276 fstat(fh, &stat);
277 return stat.st_size;
278 #endif
279 }
280
_sys_istty(FILEHANDLE fh)281 int _sys_istty(FILEHANDLE fh)
282 {
283 if((STDIN <= fh) && (fh <= STDERR))
284 return 1;
285 else
286 return 0;
287 }
288
remove(const char * filename)289 int remove(const char *filename)
290 {
291 #ifndef RT_USING_DFS
292 return -1;
293 #else
294 return unlink(filename);
295 #endif
296 }
297
298 #if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) && defined(RT_USING_MODULE) && defined(RT_USING_DFS)
299 /* use system(const char *string) implementation in the msh */
300 #else
system(const char * string)301 int system(const char *string)
302 {
303 RT_ASSERT(0);
304 for (;;);
305 }
306 #endif
307
308 #ifdef __MICROLIB
309 #include <stdio.h>
310
fputc(int c,FILE * f)311 int fputc(int c, FILE *f)
312 {
313 char ch[2] = {0};
314
315 ch[0] = c;
316 rt_kprintf(&ch[0]);
317 return 1;
318 }
319
fgetc(FILE * f)320 int fgetc(FILE *f)
321 {
322 #ifdef RT_USING_POSIX
323 char ch;
324
325 if (libc_stdio_read(&ch, 1) == 1)
326 return ch;
327 #endif
328
329 return -1;
330 }
331 #endif
332