1570af302Sopenharmony_ci#include "stdio_impl.h"
2570af302Sopenharmony_ci#include <string.h>
3570af302Sopenharmony_ci#include "param_check.h"
4570af302Sopenharmony_ci
5570af302Sopenharmony_ci#define MIN(a,b) ((a)<(b) ? (a) : (b))
6570af302Sopenharmony_ci
7570af302Sopenharmony_ciint __fill_buffer(FILE *f)
8570af302Sopenharmony_ci{
9570af302Sopenharmony_ci	int r = __toread(f);
10570af302Sopenharmony_ci	if (r != 0) {
11570af302Sopenharmony_ci		return r;
12570af302Sopenharmony_ci	}
13570af302Sopenharmony_ci
14570af302Sopenharmony_ci	int k = f->readx(f, f->buf, f->buf_size);
15570af302Sopenharmony_ci	if (k <= 0) {
16570af302Sopenharmony_ci		f->flags |= (k == 0) ? F_EOF : F_ERR;
17570af302Sopenharmony_ci		f->rpos = f->rend;
18570af302Sopenharmony_ci		return k;
19570af302Sopenharmony_ci	}
20570af302Sopenharmony_ci
21570af302Sopenharmony_ci	f->rpos = f->buf;
22570af302Sopenharmony_ci	f->rend = f->rpos + k;
23570af302Sopenharmony_ci
24570af302Sopenharmony_ci	return 0;
25570af302Sopenharmony_ci}
26570af302Sopenharmony_ci
27570af302Sopenharmony_cisize_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f)
28570af302Sopenharmony_ci{
29570af302Sopenharmony_ci	unsigned char *dest = destv;
30570af302Sopenharmony_ci	size_t len = size * nmemb, l = len, k;
31570af302Sopenharmony_ci	PARAM_CHECK(f);
32570af302Sopenharmony_ci	if (!size) {
33570af302Sopenharmony_ci		nmemb = 0;
34570af302Sopenharmony_ci	}
35570af302Sopenharmony_ci
36570af302Sopenharmony_ci	FLOCK(f);
37570af302Sopenharmony_ci
38570af302Sopenharmony_ci	/* allocate file buffer if needed */
39570af302Sopenharmony_ci	if (__falloc_buf(f) < 0) {
40570af302Sopenharmony_ci		f->flags |= F_ERR;
41570af302Sopenharmony_ci		goto exit;
42570af302Sopenharmony_ci	}
43570af302Sopenharmony_ci
44570af302Sopenharmony_ci	f->mode |= f->mode-1;
45570af302Sopenharmony_ci
46570af302Sopenharmony_ci	while (l > 0) {
47570af302Sopenharmony_ci		if (f->rpos != f->rend) {
48570af302Sopenharmony_ci			/* First exhaust the buffer. */
49570af302Sopenharmony_ci			k = MIN(f->rend - f->rpos, l);
50570af302Sopenharmony_ci			memcpy(dest, f->rpos, k);
51570af302Sopenharmony_ci			f->rpos += k;
52570af302Sopenharmony_ci			dest += k;
53570af302Sopenharmony_ci			l -= k;
54570af302Sopenharmony_ci		}
55570af302Sopenharmony_ci		/* done */
56570af302Sopenharmony_ci		if (l == 0) {
57570af302Sopenharmony_ci			goto exit;
58570af302Sopenharmony_ci		}
59570af302Sopenharmony_ci		/* if user buffer is longer than file buffer,
60570af302Sopenharmony_ci		 * maybe buffer size is 0, non-buffer mode,
61570af302Sopenharmony_ci		 * read directly */
62570af302Sopenharmony_ci		if (l > f->buf_size) {
63570af302Sopenharmony_ci			break;
64570af302Sopenharmony_ci		}
65570af302Sopenharmony_ci
66570af302Sopenharmony_ci		if (__fill_buffer(f)) {
67570af302Sopenharmony_ci			goto exit;
68570af302Sopenharmony_ci		}
69570af302Sopenharmony_ci	}
70570af302Sopenharmony_ci
71570af302Sopenharmony_ci	/* Read the remainder directly */
72570af302Sopenharmony_ci	for (; l; l-=k, dest+=k) {
73570af302Sopenharmony_ci		k = f->readx(f, dest, l);
74570af302Sopenharmony_ci		if (!k) {
75570af302Sopenharmony_ci			break;
76570af302Sopenharmony_ci		}
77570af302Sopenharmony_ci	}
78570af302Sopenharmony_ci
79570af302Sopenharmony_ciexit:
80570af302Sopenharmony_ci	FUNLOCK(f);
81570af302Sopenharmony_ci	return (len - l) / size;
82570af302Sopenharmony_ci}
83570af302Sopenharmony_ci
84570af302Sopenharmony_ciweak_alias(fread, fread_unlocked);
85