1 /*
2  * Copyright (c) 2013 Travis Geiselbrecht
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #include <io_handle.h>
24 #include <printf.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <sys/types.h>
29 
30 #if LK_LIBC_IMPLEMENTATION_IS_LK
31 #define DEFINE_STDIO_DESC(id)   \
32     [(id)]  = {                 \
33         .io = &console_io,      \
34     }
35 
36 __WEAK FILE __stdio_FILEs[3] = {
37     DEFINE_STDIO_DESC(0), /* stdin */
38     DEFINE_STDIO_DESC(1), /* stdout */
39     DEFINE_STDIO_DESC(2), /* stderr */
40 };
41 #undef DEFINE_STDIO_DESC
42 #endif
43 
lock_write_commit_unlock(FILE * fp,const char * s,size_t length)44 static size_t lock_write_commit_unlock(FILE *fp, const char* s, size_t length)
45 {
46     size_t bytes_written;
47     io_handle_t *io = file_io_handle(fp);
48     io_lock(io);
49     bytes_written = io_write(io, s, length);
50     io_write_commit(io);
51     io_unlock(io);
52     return bytes_written;
53 }
54 
fputc(int _c,FILE * fp)55 int fputc(int _c, FILE *fp)
56 {
57     unsigned char c = _c;
58     return lock_write_commit_unlock(fp, (char *)&c, 1);
59 }
60 
putchar(int c)61 int putchar(int c)
62 {
63     return fputc(c, stdout);
64 }
65 
puts(const char * str)66 int puts(const char *str)
67 {
68     int err = fputs(str, stdout);
69     if (err >= 0)
70         err = fputc('\n', stdout);
71     return err;
72 }
73 
fputs(const char * s,FILE * fp)74 int fputs(const char *s, FILE *fp)
75 {
76     size_t len = strlen(s);
77     return lock_write_commit_unlock(fp, s, len);
78 }
79 
fwrite(const void * ptr,size_t size,size_t count,FILE * fp)80 size_t fwrite(const void *ptr, size_t size, size_t count, FILE *fp)
81 {
82     size_t bytes_written;
83 
84     if (size == 0 || count == 0)
85         return 0;
86 
87     // fast path for size == 1
88     if (likely(size == 1)) {
89         return lock_write_commit_unlock(fp, ptr, count);
90     }
91 
92     bytes_written = lock_write_commit_unlock(fp, ptr, size * count);
93     return bytes_written / size;
94 }
95 
getc(FILE * fp)96 int getc(FILE *fp)
97 {
98     char c;
99     io_handle_t *io = file_io_handle(fp);
100     ssize_t ret = io_read(io, &c, sizeof(c));
101 
102     return (ret > 0) ? c : ret;
103 }
104 
getchar(void)105 int getchar(void)
106 {
107     return getc(stdin);
108 }
109 
_fprintf_output_func(const char * str,size_t len,void * state)110 static int _fprintf_output_func(const char *str, size_t len, void *state)
111 {
112     io_handle_t *io = file_io_handle((FILE *)state);
113 
114     return io_write(io, str, len);
115 }
116 
vfprintf_worker(FILE * fp,const char * fmt,va_list ap,int filtered_on_release)117 int vfprintf_worker(FILE *fp, const char *fmt, va_list ap, int filtered_on_release)
118 {
119     io_handle_t *io = file_io_handle(fp);
120     io_lock(io);
121     int result = _printf_engine(&_fprintf_output_func, (void *)fp, fmt, ap);
122     io_write_commit(io);
123     io_unlock(io);
124     return result;
125 }
126 
fprintf(FILE * fp,const char * fmt,...)127 int fprintf(FILE *fp, const char *fmt, ...)
128 {
129     va_list ap;
130     int err;
131 
132     va_start(ap, fmt);
133     err = vfprintf(fp, fmt, ap);
134     va_end(ap);
135     return err;
136 }
137 
printf(const char * fmt,...)138 int printf(const char *fmt, ...)
139 {
140 #if DISABLE_DEBUG_OUTPUT
141     return 0;
142 #else
143     va_list ap;
144     int err;
145 
146     va_start(ap, fmt);
147     err = vfprintf(stdout, fmt, ap);
148     va_end(ap);
149 
150     return err;
151 #endif
152 }
153 
vprintf(const char * fmt,va_list ap)154 int vprintf(const char *fmt, va_list ap)
155 {
156 #if DISABLE_DEBUG_OUTPUT
157     return 0;
158 #else
159     return vfprintf(stdout, fmt, ap);
160 #endif
161 }
162 
163 #if LK_LIBC_IMPLEMENTATION_IS_LK
fflush(FILE * stream)164 int fflush(FILE *stream) {
165     /* nothing to flush; output streams aren't buffered */
166     return 0;
167 }
168 #endif
169