]> git.saurik.com Git - apple/libc.git/blobdiff - libdarwin/stdio.c
Libc-1353.41.1.tar.gz
[apple/libc.git] / libdarwin / stdio.c
index 49bfd852985f2eee4d099b4f0c5ea68ba0cc4145..c1d1585e73521e5e04af1c1d4ffce973203a0eb8 100644 (file)
 #include "internal.h"
 
 #pragma mark API
+int
+fcheck_np(FILE *f, size_t n, size_t expected)
+{
+       if (n == expected) {
+               return 0;
+       }
+       if (feof(f)) {
+               return EOF;
+       }
+       if (ferror(f)) {
+               return 1;
+       }
+       __builtin_unreachable();
+}
+
+os_fd_t
+dup_np(os_fd_t fd)
+{
+       os_fd_t dfd = -1;
+
+       while (true) {
+               dfd = dup(fd);
+
+               if (os_fd_valid(dfd)) {
+                       break;
+               }
+
+               switch (errno) {
+               case EINTR:
+                       break;
+               case EBADF:
+                       os_crash("bad fd");
+               case EMFILE:
+               case ENFILE:
+                       os_crash("failed to dup fd");
+               default:
+                       os_crash("unhandled error: %s", symerror_np(errno));
+               }
+       }
+
+       return dfd;
+}
+
 size_t
 zsnprintf_np(char *buff, size_t len, const char *fmt, ...)
 {
@@ -41,3 +84,136 @@ zsnprintf_np(char *buff, size_t len, const char *fmt, ...)
 
        return (size_t)np;
 }
+
+void
+crfprintf_np(FILE *f, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vcrfprintf_np(f, fmt, ap);
+       va_end(ap);
+}
+
+void
+vcrfprintf_np(FILE *f, const char *fmt, va_list ap)
+{
+       vfprintf(f, fmt, ap);
+       fprintf(f, "\n");
+}
+
+void
+wfprintf_np(FILE *f, ssize_t initpad, size_t pad, size_t width,
+               const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vwfprintf_np(f, initpad, pad, width, fmt, ap);
+       va_end(ap);
+}
+
+void
+vwfprintf_np(FILE *f, ssize_t initpad, size_t pad, size_t width,
+               const char *fmt, va_list ap)
+{
+       char *__os_free string = NULL;
+       char *__os_free working = NULL;
+       char *__os_free init_padding = NULL;
+       char *__os_free padding = NULL;
+       const char *curline = NULL;;
+       size_t left = 0;
+       size_t initpad_labs = (size_t)labs(initpad);
+       int ret = -1;
+
+       if (width && width <= pad) {
+               os_crash("width cannot be smaller than pad");
+       }
+       if (width && (initpad > 0) && width <= initpad_labs) {
+               os_crash("width cannot be smaller than initpad");
+       }
+       if (width && (initpad < 0) && width <= initpad_labs) {
+               os_crash("width cannot be smaller than negative initpad");
+       }
+
+       ret = vasprintf(&string, fmt, ap);
+       if (ret < 0 || !string) {
+               return;
+       }
+
+       left = (size_t)ret;
+       curline = string;
+
+       // The working buffer will always be large enough to handle any individual
+       // line. vasprintf(3) returns the number of characters printed not including
+       // the null terminator, so add space for that.
+       working = malloc(left + 1);
+       if (!working) {
+               return;
+       }
+
+       init_padding = malloc(initpad_labs + 1);
+       if (!init_padding) {
+               return;
+       }
+
+       if (initpad >= 0) {
+               memset(init_padding, ' ', initpad);
+               init_padding[initpad] = 0;
+       } else {
+               init_padding[0] = 0;
+       }
+
+       padding = malloc(pad + 1);
+       if (!padding) {
+               return;
+       }
+
+       memset(padding, ' ', pad);
+       padding[pad] = 0;
+
+       do {
+               size_t which_pad = pad;
+               char *which_padding = padding;
+               bool findspace = true;
+               size_t n2consume = 0;
+               char *breakchar = NULL;
+
+               if (curline == string) {
+                       which_padding = init_padding;
+                       which_pad = initpad_labs;
+               }
+
+               if (width == 0) {
+                       // Width is unconstrained so just consume the entire string and
+                       // indent any new lines within.
+                       n2consume = left;
+                       findspace = false;
+               } else {
+                       n2consume = width - which_pad;
+                       if (n2consume >= left) {
+                               n2consume = left;
+                               findspace = false;
+                       }
+               }
+
+               strlcpy(working, curline, n2consume + 1);
+               breakchar = strchr(working, '\n');
+               if (!breakchar && findspace) {
+                       // No new line within our maximally-constrained width of characters,
+                       // so search for a space instead.
+                       breakchar = strrchr(working, ' ');
+               }
+
+               if (breakchar) {
+                       // Found something to break on, so nerf it and only consume the
+                       // characters up until that break character.
+                       *breakchar = 0;
+                       n2consume = (size_t)(breakchar - working);
+                       curline += n2consume + 1;
+               }
+
+               fprintf(f, "%s%s\n", which_padding, working);
+               left -= n2consume;
+       } while (left);
+}