Ejemplo n.º 1
0
int
mvfprintf(
	FILE *		fp,
	const char *	fmt,
	va_list		ap
	)
{
#ifndef VSNPRINTF_PERCENT_M
	char		nfmt[256];
#else
	const char *	nfmt = fmt;
#endif
	int		errval;

	/*
	 * Save the error value as soon as possible
	 */
#ifdef SYS_WINNT
	errval = GetLastError();
	if (NO_ERROR == errval)
#endif /* SYS_WINNT */
		errval = errno;

#ifndef VSNPRINTF_PERCENT_M
	format_errmsg(nfmt, sizeof(nfmt), fmt, errval);
#else
	errno = errval;
#endif
	return vfprintf(fp, nfmt, ap);
}
Ejemplo n.º 2
0
Archivo: msyslog.c Proyecto: Darge/ntp
void
test_format_errmsgHangingPercent(void) {
#ifndef VSNPRINTF_PERCENT_M
	static char fmt[] = "percent then nul term then non-nul %\0oops!";
	char act_buf[64];

	ZERO(act_buf);
	format_errmsg(act_buf, sizeof(act_buf), fmt, ENOENT);

	TEST_ASSERT_EQUAL_STRING(fmt, act_buf);
	TEST_ASSERT_EQUAL_STRING("", act_buf + 1 + strlen(act_buf));
#else
	TEST_IGNORE_MESSAGE("VSNPRINTF_PERCENT_M is defined")
#endif
}
Ejemplo n.º 3
0
/* the actual string format parser
 * Although it's not in the documentation of `printf()`, but in addition to the
 * `%d` conversion specifier, this supports `%i`, which takes an `int` argument
 * instead of a `long`. It is used only for formatting error messages (since
 * Sparkling integers are all `long`s), but feel free to use it yourself.
 *
 * if `errmsg' is not a NULL pointer, and an error occurred while creating the
 * format string, then on return, `*errmsg' will point to a string containing
 * a message that describes the error.
 */
static char *make_format_string(
	const char *fmt,
	size_t *len,
	int argc,
	void *argv,
	int isval,
	char **errmsg
)
{
	struct string_builder bld;
	int argidx = 0;
	const char *s = fmt;
	const char *p = s;	/* points to the beginning of the next
				 * non-format part of the format string
				 */

	init_builder(&bld);

	while (*s) {
		if (*s == '%') {
			struct format_args args;
			init_format_args(&args);

			/* append preceding non-format string chunk */
			if (s > p) {
				append_string(&bld, p, s - p);
			}

			s++;

			/* Actually parse the format string.
			 * '#' flag: prepend base prefix (0b, 0, 0x)
			 */
			if (*s == '#') {
				args.flags |= FLAG_BASEPREFIX;
				s++;
			}

			/* ' ' (space) flag: prepend space if non-negative
			 * '+' flag: always prepend explicit + or - sign
			 */
			if (*s == ' ') {
				args.flags |= FLAG_PADSIGN;
				s++;
			} else if (*s == '+') {
				args.flags |= FLAG_EXPLICITSIGN;
				s++;
			}

			/* leading 0 flag: pad field with zeroes */
			if (*s == '0') {
				args.flags |= FLAG_ZEROPAD;
				s++;
			}

			/* field width specifier */
			if (isdigit(*s)) {
				args.width = 0;
				while (isdigit(*s)) {
					args.width *= 10;
					args.width += *s++ - '0';
				}
			} else if (*s == '*') {
				s++;
				if (isval) {
					SpnValue *widthptr;

					/* check argc if the caller wants us to do so */
					if (argc >= 0 && argidx >= argc) {
						format_errmsg(errmsg, OUT_OF_ARGUMENTS, argidx);
						free(bld.buf);
						return NULL;
					}

					/* width specifier must be an integer */
					widthptr = getarg_val(argv, &argidx);
					if (!isnum(widthptr)) {
					 	format_errmsg(
					 		errmsg,
					 		TYPE_MISMATCH,
					 		argidx,
					 		SPN_TTAG_NUMBER,
					 		widthptr->type
					 	);
						free(bld.buf);
						return NULL;
					}

					if (isfloat(widthptr)) {
				 		format_errmsg(
				 			errmsg,
				 			EXPECT_INTEGER,
				 			argidx
				 		);
						free(bld.buf);
						return NULL;
					}

					args.width = intvalue(widthptr);
				} else {
					const int *widthptr = getarg_raw(argv, &argidx);
					args.width = *widthptr;
				}
			}

			/* precision/maximal length specifier */
			if (*s == '.') {
				s++;

				if (*s == '+') {
					args.flags |= FLAG_EXPONENTSIGN;
					s++;
				}

				args.precision = 0;
				if (isdigit(*s)) {
					while (isdigit(*s)) {
						args.precision *= 10;
						args.precision += *s++ - '0';
					}
				} else if (*s == '*') {
					s++;
					if (isval) {
						SpnValue *precptr;

						/* check argc if the caller wants us to do so */
						if (argc >= 0 && argidx >= argc) {
							format_errmsg(errmsg, OUT_OF_ARGUMENTS, argidx);
							free(bld.buf);
							return NULL;
						}

						/* precision must be an integer too */
						precptr = getarg_val(argv, &argidx);

						if (!isnum(precptr)) {
							format_errmsg(
								errmsg,
								TYPE_MISMATCH,
								argidx,
								SPN_TTAG_NUMBER,
								precptr->type
							);
							free(bld.buf);
							return NULL;
						}

						if (isfloat(precptr)) {
					 		format_errmsg(
					 			errmsg,
					 			EXPECT_INTEGER,
					 			argidx
					 		);
							free(bld.buf);
							return NULL;
						}

						args.precision = intvalue(precptr);
					} else {
						const int *precptr = getarg_raw(argv, &argidx);
						args.precision = *precptr;
					}
				}
			}

			args.spec = *s++;

			/* check argc if the caller wants us to do so */
			if (argc >= 0 && argidx >= argc) {
				format_errmsg(errmsg, OUT_OF_ARGUMENTS, argidx);
				free(bld.buf);
				return NULL;
			}

			/* append parsed format string */
			if (append_format(&bld, &args, argv, &argidx, isval, errmsg) != 0) {
				free(bld.buf);
				return NULL;
			}

			/* update non-format chunk base pointer */
			p = s;
		} else {
			s++;
		}
	}

	/* if the format string doesn't end with a conversion specifier,
	 * then just append the last non-format (literal) string chunk
	 */
	if (s > p) {
		append_string(&bld, p, s - p);
	}

	/* append terminating NUL byte */
	expand_buffer(&bld, 1);
	bld.buf[bld.len] = 0;

	if (len != NULL) {
		*len = bld.len;
	}

	return bld.buf;
}
Ejemplo n.º 4
0
/* returns zero on success, nonzero on error */
static int append_format(
	struct string_builder *bld,
	const struct format_args *args,
	void *argv,
	int *argidx,
	int isval,
	char **errmsg
)
{
	switch (args->spec) {
	case '%':
		append_string(bld, "%", 1);
		break;
	case 's': {
		const char *str;
		size_t len;

		if (isval) {
			SpnString *strobj;

			/* must be a string */
			SpnValue *val = getarg_val(argv, argidx);
			if (!isstring(val)) {
				format_errmsg(
					errmsg,
					TYPE_MISMATCH,
					*argidx,
					SPN_TYPE_STRING,
					val->type
				);
				return -1;
			}

			strobj = stringvalue(val);
			str = strobj->cstr;
			len = strobj->len;
		} else {
			str = getarg_raw(argv, argidx);
			len = strlen(str);
		}

		if (args->precision >= 0 && args->precision < len) {
			len = args->precision;
		}

		if (args->width >= 0 && args->width > len) {
			size_t pad = args->width - len;
			expand_buffer(bld, pad);

			while (pad-- > 0) {
				bld->buf[bld->len++] = ' ';
			}
		}

		append_string(bld, str, len);
		break;
	}
	case 'i':
	case 'd':
	case 'b':
	case 'o':
	case 'u':
	case 'x':
	case 'X': {
		char *buf, *end, *begin;
		size_t len = PR_LONG_DIGITS;
		enum format_flags flags = args->flags;
		unsigned base = base_for_specifier(args->spec);
		long n;
		unsigned long u;

		if (isval) {
			/* must be a number */
			SpnValue *val = getarg_val(argv, argidx);
			if (!isnum(val)) {
				format_errmsg(
					errmsg,
					TYPE_MISMATCH,
					*argidx,
					SPN_TTAG_NUMBER,
					val->type
				);
				return -1;
			}

			if (isint(val)) {
				n = intvalue(val);
			} else {
				n = floatvalue(val); /* truncate */
			}
		} else {
			/* "%i" expects an int, others expect a long */
			if (args->spec == 'i') {
				n = *(const int *)getarg_raw(argv, argidx);
			} else {
				n = *(const long *)getarg_raw(argv, argidx);
			}
		}

		if (args->spec == 'i' || args->spec == 'd') {
			/* signed conversion specifiers */
			if (n < 0) {
				flags |= FLAG_NEGATIVE;
				u = -n;
			} else {
				u = n;
			}
		} else {
			/* unsigned conversion specifiers */
			u = n;
		}

		if (args->spec == 'X') {
			flags |= FLAG_CAPS;
		}

		if (args->width >= 0 && args->width > len) {
			len = args->width;
		}

		buf = spn_malloc(len);
		end = buf + len;
		begin = ulong2str(end, u, base, args->width, flags);

		assert(buf <= begin);
		append_string(bld, begin, end - begin);
		free(buf);

		break;
	}
	case 'c': {
		unsigned char ch;
		int len = 1; /* one character is one character long... */

		if (isval) {
			/* must be an integer */
			SpnValue *val = getarg_val(argv, argidx);

			if (!isnum(val)) {
				format_errmsg(
					errmsg,
					TYPE_MISMATCH,
					*argidx,
					SPN_TTAG_NUMBER,
					val->type
				);
				return -1;
			}

			if (isfloat(val)) {
				format_errmsg(errmsg, EXPECT_INTEGER, *argidx);
				return -1;
			}

			ch = intvalue(val);
		} else {
			ch = *(const long *)getarg_raw(argv, argidx);
		}

		if (args->width > len) {
			len = args->width;
		}

		expand_buffer(bld, len);

		while (len-- > 1) {
			bld->buf[bld->len++] = ' ';
		}

		bld->buf[bld->len++] = ch;

		break;
	}
	case 'f':
	case 'F': {
		char *buf, *end, *begin;
		size_t len;
		int prec;
		double x;
		enum format_flags flags = args->flags;

		if (isval) {
			SpnValue *val = getarg_val(argv, argidx);
			if (!isnum(val)) {
				format_errmsg(
					errmsg,
					TYPE_MISMATCH,
					*argidx,
					SPN_TTAG_NUMBER,
					val->type
				);
				return -1;
			}

			if (isfloat(val)) {
				x = floatvalue(val);
			} else {
				x = intvalue(val);
			}
		} else {
			x = *(const double *)getarg_raw(argv, argidx);
		}

		if (args->spec == 'F') {
			flags |= FLAG_CAPS;
		}

		/* handle special cases */
		if (+1.0 / x == +1.0 / -0.0) {
			/* negative zero: set sign flag and carry on */
			flags |= FLAG_NEGATIVE;
		} else if (
			x != x		/*  NaN */
		     || x == +1.0 / 0.0	/* +inf */
		     || x == -1.0 / 0.0	/* -inf */
		) {
			print_special_fp(bld, flags, args->width, x);
			break;
		}

		if (x < 0.0) {
			flags |= FLAG_NEGATIVE;
			x = -x;
		}

		/* at this point, `x' is non-negative or -0 */

		if (x >= 1.0) {
			len = ceil(log10(x)) + 1; /* 10 ^ n is n + 1 digits long */
		} else {
			len = 1; /* leading zero needs exactly one character */
		}

		prec = args->precision < 0 ? DBL_DIG : args->precision;

		len += prec + 3; /* decimal point, sign, leading zero */

		if (args->width >= 0 && args->width > len) {
			len = args->width;
		}

		buf = spn_malloc(len);
		end = buf + len;
		begin = double2str(end, x, args->width, prec, flags);

		assert(buf <= begin);
		append_string(bld, begin, end - begin);
		free(buf);

		break;
	}
	case 'B': {
		int boolval;
		const char *str;
		size_t len;

		if (isval) {
			/* must be a boolean */
			SpnValue *val = getarg_val(argv, argidx);
			if (!isbool(val)) {
				format_errmsg(
					errmsg,
					TYPE_MISMATCH,
					*argidx,
					SPN_TTAG_BOOL,
					val->type
				);
				return -1;
			}

			boolval = boolvalue(val);
		} else {
			boolval = *(const int *)getarg_raw(argv, argidx);
		}

		str = boolval ? "true" : "false";
		len = strlen(str);

		if (args->precision >= 0 && args->precision < len) {
			len = args->precision;
		}

		if (args->width >= 0 && args->width > len) {
			size_t pad = args->width - len;
			expand_buffer(bld, pad);

			while (pad-- > 0) {
				bld->buf[bld->len++] = ' ';
			}
		}

		append_string(bld, str, len);
		break;
	}
	default:
		format_errmsg(errmsg, INVALID_SPECIFIER, ++*argidx, args->spec);
		return -1;
	}

	return 0;
}
Ejemplo n.º 5
0
const char *
Test::start (const char *name)
{
  if (this->running_)
    return "Already running\n";

  const char *msg = 0;

  // Reset test status to not inadvertantly report a previous test.
  this->status_ = -1;
  this->cleanup ();     // Resets cmdline_, argc_, argv_

  // The command line is part-way through being tokenized by strtok(). It
  // left off after the program name. Anything remaining are the command
  // line arguments for the program. Pick off whatever is there, copy it
  // to the cmdline_ array and fill in argc_/argv_ for the eventual run.
  strcpy (this->name_, name);
  this->argv_[0] = this->name_;
  this->argc_ = 1;
  size_t cmdchars = 0;
  for (char *token = strtok (0, "\t \n\r");
       token != 0 && (cmdchars + strlen (token) + 1) < CMDLINE_LEN;
       token = strtok (0, "\t \n\r"))
    {
      // We have a new token and it will fit in cmdline_. Copy it to the
      // next spot in cmdline_, add it to argv_/argc_ then update cmdchars
      // to account for the copied-in token and its nul terminator.
      strcpy (&this->cmdline_[cmdchars], token);
      this->argv_[this->argc_] = &this->cmdline_[cmdchars];
      ++this->argc_;
      cmdchars += (strlen (token) + 1);
    }
  char libspec[1024];
  sprintf (libspec, "%s.dll", name);
  if ((this->dll_handle_ = LoadLibrary (libspec)) == NULL)
    return format_errmsg (GetLastError (), libspec);

  this->entry_ = (TEST_FUNC) GetProcAddress (this->dll_handle_, "main");
  if (this->entry_ == NULL)
    {
      msg = format_errmsg (GetLastError (), "main");
      this->cleanup ();
      return msg;
    }
  else
    {
      unsigned int thread_id; /* unused */
      uintptr_t h = _beginthreadex (0,             // security
                                    1024 * 1024,   // stack size
                                    run_test,      // entrypoint
                                    (void *)this,  // arglist
                                    0,             // initflag
                                    &thread_id);   // thread ID
      this->thr_handle_ = (HANDLE) h;
      if (h == 0)         // Test thread may have access to thr_handle_
        {
          msg = format_errmsg (GetLastError (), "spawn");
          this->cleanup ();
          return msg;
        }
    }
  return 0;
}
Ejemplo n.º 6
0
int
Peer::command (void)
{
  // The protocol exchanges with the peer are execpted to be lock-step
  // request-reply command lines, so we can make assumptions about a complete
  // line being available to make life easier.
  const int MAX_RECV = 1024;
  char line[MAX_RECV], *p;
  p = &line[0];
  int count = 0, len = 0;
  while ((count = recv (this->handle_, p, MAX_RECV - len, 0)) > 0)
    {
      p[count] = '\0';
      len += count;
      p += count;
      char *nl;
      if ((nl = strchr (line, '\n')) == 0)
        continue;

      // At this point we have a 0-terminated string with a newline ending
      // the command line. Break out and process the command.
      break;
    }
  if (count <= 0)
    return -1;         // Relay closed/error socket to caller

  char *cmd = strtok (line, "\t \n\r");
  if (cmd == 0)
    {
      char err[1024];
      sprintf (err, "Can't parse input: %s\n", line);
      this->reply (err);
      return -1;
    }
  // Which command is it? These commands are known:
  //
  //   run <test-dll> [args]
  //     Run test in the named test-dll; respond with "OK" or an error string.
  //   status
  //     If test still running return "RUNNING" else return exit status.
  //   wait
  //     Wait for test to exit; return "OK"
  //   kill
  //     Kill the thread with the most recent test; return "OK".
  //   snaplog
  //     Take a snapshot of the current stdout/stderr log to a new file
  //     name and reset the stdout/stderr log.
  if (strcmp ("run", cmd) == 0)
    {
      char *test = strtok (0, "\t \n\r");
      if (test == 0)
        {
          this->reply ("Malformed run command\n");
          return -1;
        }
      // start() pulls apart the rest of the command line...
      const char *errmsg = this->test_.start (test);
      if (errmsg == 0)
        this->reply ("OK\n");
      else
        this->reply (errmsg);
    }
  else if (strcmp ("status", cmd) == 0)
    {
      int status;
      if (this->test_.status (&status))
        {
          char retvalmsg[64];
          sprintf (retvalmsg, "%d\n", status);
          this->reply (retvalmsg);
        }
      else
        this->reply ("RUNNING\n");
    }
  else if (strcmp ("wait", cmd) == 0)
    {
      int status = this->test_.wait ();
      char retvalmsg[64];
      sprintf (retvalmsg, "%d\n", status);
      this->reply (retvalmsg);
    }
  else if (strcmp ("kill", cmd) == 0)
    {
      // Killing things is bad... say we can't and the host should reboot us.
      this->reply ("NO - please reboot me\n");
    }
  else if (strcmp ("waitforfile", cmd) == 0)
    {
      char *name = strtok (0, "\t \n\r");
      if (name == 0)
        {
          this->reply ("Malformed waitforfile command\n");
          return -1;
        }
      char *secs_s = strtok (0, "\t \n\r");
      int secs = 0;
      if (secs_s == 0 || (secs = atoi (secs_s)) <= 0)
        {
          this->reply ("Malformed waitforfile command\n");
          return -1;
        }
      struct _stat info;
      const char *msg = 0;
      bool found = false;
      while (secs > 0)
        {
          if (_stat (name, &info) == -1)   // No file yet
            {
              if (errno != ENOENT)
                {
                  // Something more serious than no file yet; bail out.
                  msg = format_errmsg (errno, name);
                  break;
                }
            }
          else
            {
              if (info.st_size > 0)
                {
                  found = true;
                  break;
                }
            }
          // Either no file yet, or it's there but with no content yet.
          Sleep (1 * 1000);     // arg is in msec
          --secs;
        }
      if (found)
        this->reply ("OK\n");
      else if (secs == 0)
        this->reply ("TIMEOUT\n");
      else
        this->reply (msg);
    }
  else if (strcmp ("snaplog", cmd) == 0)
    {
      if (logf == INVALID_HANDLE_VALUE)
        {
          this->reply ("NONE\n");
        }
      else
        {
          CloseHandle (logf);
          if (0 == rename (LogName, "snapshot.txt"))
            {
              char abspath[1024];
              if (_fullpath (abspath, "snapshot.txt", 1024))
                {
                  strcat (abspath, "\n");
                  this->reply (abspath);
                }
              else
                {
                  // Last ditch effort to get a name back to the client
                  this->reply ("\\ni-rt\\system\\snapshot.txt\n");
                }
            }
          else
            {
              this->reply ("NONE\n");
            }
          // Reset stdout/stderr to a new file
          logf = CreateFile (LogName,
                             FILE_ALL_ACCESS,
                             FILE_SHARE_READ,
                             0,    // security
                             CREATE_ALWAYS,
                             FILE_ATTRIBUTE_NORMAL,
                             0);
          SetStdHandle (STD_OUTPUT_HANDLE, logf);
          SetStdHandle (STD_ERROR_HANDLE, logf);
        }
    }
  else
    {
      this->reply ("Unrecognized command\n");
      return -1;
    }
  return 0;
}