//----------------------------------------------------------------------------// // GNU GPL OS/K // // // // Desc: Buffer library // // // // // // Copyright © 2018-2019 The OS/K Team // // // // This file is part of OS/K. // // // // OS/K is free software: you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation, either version 3 of the License, or // // any later version. // // // // OS/K is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY//without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License for more details. // // // // You should have received a copy of the GNU General Public License // // along with OS/K. If not, see . // //----------------------------------------------------------------------------// #include // // Builds string reading from buf according to fmt // size_t BScanFromBuf(Buffer_t *buf, const char *fmt, ...) { size_t sz; va_list ap; va_start(ap, fmt); ExAcquireLock(&buf->lock); sz = vbscanf(buf, fmt, ap); ExReleaseLock(&buf->lock); va_end(ap); return sz; } size_t BScanFromBufV(Buffer_t *buf, const char *fmt, va_list ap) { size_t sz; ExAcquireLock(&buf->lock); sz = vbscanf(buf, fmt, ap); ExReleaseLock(&buf->lock); return sz; } size_t bscanf(Buffer_t *buf, const char *fmt, ...) { size_t sz; va_list ap; va_start(ap, fmt); sz = vbscanf(buf, fmt, ap); va_end(ap); return sz; } size_t vbscanf(Buffer_t *buf, const char *fmt, va_list ap) { error_t rc = EOK; size_t readcnt = 0; uchar ch = 0; char *chptr; bool l, h; size_t width; bool ignore; // '*' modifier, don't write to va_list for current mod if (!buf || !fmt) { seterrno(EINVAL); return 0; } if (buf->flags & (BF_EOF|BF_ERR)) { seterrno(EENDF); return 0; } if (buf->state != BS_RDWR && buf->state != BS_WRONLY) { seterrno(EBADF); return 0; } // Progress in format string while (*fmt && !rc) { // Skip all kinds of whitespaces if (isspace(*fmt)) { another_space: rc = bgetc(buf, &ch); if (!rc) break; // Put back non-whitespaces and progress if (!isspace(ch)) { buf->rp--; do { fmt++; } while (isspace(*fmt)); continue; } else goto another_space; } // Deal with all non-'%' non-whitespace characters if (*fmt != '%') { rc = bgetc(buf, &ch); // Is it what we expected? if (!rc && ch != *fmt) { // No, so put it back buf->rp--; break; } // We don't do anything with these characters continue; } // // %[*][width][modifier]type // // Skip the % fmt++; // '%%' type if (*fmt == '%') { rc = bgetc(buf, &ch); if (!rc && ch != '%') { buf->rp--; break; } continue; } l = h = 0; width = 0; ignore = 0; // Don't write to variable if (*fmt == '*') { ignore = 1; fmt++; } // Extract width field while (isdigit(*fmt)) { width = 10 * width + (*fmt - '0'); fmt++; } // // Extract length field // if (*fmt == 'l') { l = 1; fmt++; } else if (*fmt == 'h') { h = 1; fmt++; } // // Types // // Read character(s) if (*fmt == 'c') { if (width == 0) width = 1; // For >1 width, read that many characters // then store them in successive argument pointers for (; width; width--) { rc = bgetc(buf, &ch); if (!rc) break; if (ignore) continue; chptr = va_arg(ap, char *); *chptr = (char)ch; readcnt++; } } // Decimal integer else if (*fmt == 'd') { ; } } // For debugging purposes assert(!rc && "vbscanf() error"); seterrno(rc); return readcnt; }