1 /* mbed Microcontroller Library
2 * Copyright (c) 2006-2013 ARM Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "FileHandle.h"
18 #include "FileSystemLike.h"
20 #include "serial_api.h"
23 #if defined(__ARMCC_VERSION)
25 # define PREFIX(x) _sys##x
26 # define OPEN_MAX _SYS_OPEN
28 # pragma import(__use_full_stdio)
31 #elif defined(__ICCARM__)
33 # define PREFIX(x) _##x
36 # define STDIN_FILENO 0
37 # define STDOUT_FILENO 1
38 # define STDERR_FILENO 2
41 # include <sys/stat.h>
42 # include <sys/unistd.h>
43 # include <sys/syslimits.h>
49 extern const char __stdin_name
[] = "/stdin";
50 extern const char __stdout_name
[] = "/stdout";
51 extern const char __stderr_name
[] = "/stderr";
53 /* newlib has the filehandle field in the FILE struct as a short, so
54 * we can't just return a Filehandle* from _open and instead have to
55 * put it in a filehandles array and return the index into that array
56 * (or rather index+3, as filehandles 0-2 are stdin/out/err).
58 static FileHandle
*filehandles
[OPEN_MAX
];
60 FileHandle::~FileHandle() {
61 /* Remove all open filehandles for this */
62 for (unsigned int fh_i
= 0; fh_i
< sizeof(filehandles
)/sizeof(*filehandles
); fh_i
++) {
63 if (filehandles
[fh_i
] == this) {
64 filehandles
[fh_i
] = NULL
;
70 extern int stdio_uart_inited
;
71 extern serial_t stdio_uart
;
74 static void init_serial() {
76 if (stdio_uart_inited
) return;
77 serial_init(&stdio_uart
, STDIO_UART_TX
, STDIO_UART_RX
);
78 serial_format(&stdio_uart
, 8, ParityNone
, 1);
79 serial_baud(&stdio_uart
, 9600);
83 static inline int openmode_to_posix(int openmode
) {
85 #ifdef __ARMCC_VERSION
86 if (openmode
& OPEN_PLUS
) {
88 } else if(openmode
& OPEN_W
) {
90 } else if(openmode
& OPEN_A
) {
91 posix
= O_WRONLY
|O_APPEND
;
95 /* a, w, a+, w+ all create if file does not already exist */
96 if (openmode
& (OPEN_A
|OPEN_W
)) {
99 /* w and w+ truncate */
100 if (openmode
& OPEN_W
) {
103 #elif defined(__ICCARM__)
104 switch (openmode
& _LLIO_RDWRMASK
) {
105 case _LLIO_RDONLY
: posix
= O_RDONLY
; break;
106 case _LLIO_WRONLY
: posix
= O_WRONLY
; break;
107 case _LLIO_RDWR
: posix
= O_RDWR
; break;
109 if (openmode
& _LLIO_CREAT
) posix
|= O_CREAT
;
110 if (openmode
& _LLIO_APPEND
) posix
|= O_APPEND
;
111 if (openmode
& _LLIO_TRUNC
) posix
|= O_TRUNC
;
116 extern "C" FILEHANDLE
PREFIX(_open
)(const char* name
, int openmode
) {
117 /* Use the posix convention that stdin,out,err are filehandles 0,1,2.
119 if (std::strcmp(name
, __stdin_name
) == 0) {
122 } else if (std::strcmp(name
, __stdout_name
) == 0) {
125 } else if (std::strcmp(name
,__stderr_name
) == 0) {
130 // find the first empty slot in filehandles
132 for (fh_i
= 0; fh_i
< sizeof(filehandles
)/sizeof(*filehandles
); fh_i
++) {
133 if (filehandles
[fh_i
] == NULL
) break;
135 if (fh_i
>= sizeof(filehandles
)/sizeof(*filehandles
)) {
141 /* FILENAME: ":0x12345678" describes a FileLike* */
142 if (name
[0] == ':') {
144 sscanf(name
, ":%p", &p
);
145 res
= (FileHandle
*)p
;
147 /* FILENAME: "/file_system/file_name" */
154 FileSystemLike
*fs
= path
.fileSystem();
155 if (fs
== NULL
) return -1;
156 int posix_mode
= openmode_to_posix(openmode
);
157 res
= fs
->open(path
.fileName(), posix_mode
); /* NULL if fails */
161 if (res
== NULL
) return -1;
162 filehandles
[fh_i
] = res
;
164 return fh_i
+ 3; // +3 as filehandles 0-2 are stdin/out/err
167 extern "C" int PREFIX(_close
)(FILEHANDLE fh
) {
168 if (fh
< 3) return 0;
170 FileHandle
* fhc
= filehandles
[fh
-3];
171 filehandles
[fh
-3] = NULL
;
172 if (fhc
== NULL
) return -1;
177 #if defined(__ICCARM__)
178 extern "C" size_t __write (int fh
, const unsigned char *buffer
, size_t length
) {
180 extern "C" int PREFIX(_write
)(FILEHANDLE fh
, const unsigned char *buffer
, unsigned int length
, int mode
) {
182 int n
; // n is the number of bytes written
185 if (!stdio_uart_inited
) init_serial();
186 for (unsigned int i
= 0; i
< length
; i
++) {
187 serial_putc(&stdio_uart
, buffer
[i
]);
192 FileHandle
* fhc
= filehandles
[fh
-3];
193 if (fhc
== NULL
) return -1;
195 n
= fhc
->write(buffer
, length
);
197 #ifdef __ARMCC_VERSION
204 #if defined(__ICCARM__)
205 extern "C" size_t __read (int fh
, unsigned char *buffer
, size_t length
) {
207 extern "C" int PREFIX(_read
)(FILEHANDLE fh
, unsigned char *buffer
, unsigned int length
, int mode
) {
209 int n
; // n is the number of bytes read
211 // only read a character at a time from stdin
213 *buffer
= serial_getc(&stdio_uart
);
217 FileHandle
* fhc
= filehandles
[fh
-3];
218 if (fhc
== NULL
) return -1;
220 n
= fhc
->read(buffer
, length
);
222 #ifdef __ARMCC_VERSION
229 #ifdef __ARMCC_VERSION
230 extern "C" int PREFIX(_istty
)(FILEHANDLE fh
)
232 extern "C" int _isatty(FILEHANDLE fh
)
235 /* stdin, stdout and stderr should be tty */
236 if (fh
< 3) return 1;
238 FileHandle
* fhc
= filehandles
[fh
-3];
239 if (fhc
== NULL
) return -1;
241 return fhc
->isatty();
245 #if defined(__ARMCC_VERSION)
246 int _sys_seek(FILEHANDLE fh
, long position
)
247 #elif defined(__ICCARM__)
248 long __lseek(int fh
, long offset
, int whence
)
250 int _lseek(FILEHANDLE fh
, int offset
, int whence
)
253 if (fh
< 3) return 0;
255 FileHandle
* fhc
= filehandles
[fh
-3];
256 if (fhc
== NULL
) return -1;
258 #if defined(__ARMCC_VERSION)
259 return fhc
->lseek(position
, SEEK_SET
);
261 return fhc
->lseek(offset
, whence
);
265 #ifdef __ARMCC_VERSION
266 extern "C" int PREFIX(_ensure
)(FILEHANDLE fh
) {
267 if (fh
< 3) return 0;
269 FileHandle
* fhc
= filehandles
[fh
-3];
270 if (fhc
== NULL
) return -1;
275 extern "C" long PREFIX(_flen
)(FILEHANDLE fh
) {
276 if (fh
< 3) return 0;
278 FileHandle
* fhc
= filehandles
[fh
-3];
279 if (fhc
== NULL
) return -1;
286 #if !defined(__ARMCC_VERSION) && !defined(__ICCARM__)
287 extern "C" int _fstat(int fd
, struct stat
*st
) {
288 if ((STDOUT_FILENO
== fd
) || (STDERR_FILENO
== fd
) || (STDIN_FILENO
== fd
)) {
289 st
->st_mode
= S_IFCHR
;
299 extern "C" int remove(const char *path
) {
301 FileSystemLike
*fs
= fp
.fileSystem();
302 if (fs
== NULL
) return -1;
304 return fs
->remove(fp
.fileName());
307 extern "C" int rename(const char *oldname
, const char *newname
) {
311 extern "C" char *tmpnam(char *s
) {
315 extern "C" FILE *tmpfile() {
320 #ifdef __ARMCC_VERSION
321 extern "C" char *_sys_command_string(char *cmd
, int len
) {
326 extern "C" DIR *opendir(const char *path
) {
327 /* root dir is FileSystemLike */
328 if (path
[0] == '/' && path
[1] == 0) {
329 return FileSystemLike::opendir();
333 FileSystemLike
* fs
= fp
.fileSystem();
334 if (fs
== NULL
) return NULL
;
336 return fs
->opendir(fp
.fileName());
339 extern "C" struct dirent
*readdir(DIR *dir
) {
340 return dir
->readdir();
343 extern "C" int closedir(DIR *dir
) {
344 return dir
->closedir();
347 extern "C" void rewinddir(DIR *dir
) {
351 extern "C" off_t
telldir(DIR *dir
) {
352 return dir
->telldir();
355 extern "C" void seekdir(DIR *dir
, off_t off
) {
359 extern "C" int mkdir(const char *path
, mode_t mode
) {
361 FileSystemLike
*fs
= fp
.fileSystem();
362 if (fs
== NULL
) return -1;
364 return fs
->mkdir(fp
.fileName(), mode
);
367 #if defined(TOOLCHAIN_GCC_CR) || defined(TOOLCHAIN_GCC_CS) || defined(TOOLCHAIN_GCC_ARM)
368 /* prevents the exception handling name demangling code getting pulled in */
370 namespace __gnu_cxx
{
371 void __verbose_terminate_handler() {
377 // Make sure we are pulling in the retargeting module at link time
378 volatile int stdio_retargeting_module
;