Example #1
0
File: dload.c Project: moben/pacman
static size_t parse_headers(void *ptr, size_t size, size_t nmemb, void *user)
{
	size_t realsize = size * nmemb;
	const char *fptr, *endptr = NULL;
	const char * const cd_header = "Content-Disposition:";
	const char * const fn_key = "filename=";
	struct dload_payload *payload = (struct dload_payload *)user;

	if(_alpm_raw_ncmp(cd_header, ptr, strlen(cd_header)) == 0) {
		if((fptr = strstr(ptr, fn_key))) {
			fptr += strlen(fn_key);

			/* find the end of the field, which is either a semi-colon, or the end of
			 * the data. As per curl_easy_setopt(3), we cannot count on headers being
			 * null terminated, so we look for the closing \r\n */
			endptr = fptr + strcspn(fptr, ";\r\n") - 1;

			/* remove quotes */
			if(*fptr == '"' && *endptr == '"') {
				fptr++;
				endptr--;
			}

			STRNDUP(payload->content_disp_name, fptr, endptr - fptr + 1,
					RET_ERR(payload->handle, ALPM_ERR_MEMORY, realsize));
		}
	}

	return realsize;
}
Example #2
0
File: db.c Project: AdUser/xa-tags
char *
db_find_path_system(void)
{
  char *b = NULL;
  char *p = NULL;

  CALLOC(b, PATH_MAX, sizeof(char));

  snprintf(b, PATH_MAX, "%s/%s", DB_SYSTEM_PATH, DB_FILENAME);

  STRNDUP(p, b, PATH_MAX);
  FREE(b);

  return p;
}
Example #3
0
File: db.c Project: AdUser/xa-tags
char *
db_find_path_user(void)
{
  char *b = NULL;
  char *p = NULL;

  CALLOC(b, PATH_MAX, sizeof(char));

  if      ((p = getenv("XDG_DATA_HOME")) != NULL);
  else if ((p = getenv("HOME")) != NULL);
  else    msg(msg_error, MSG_U_HOMEUNSET);

  snprintf(b, PATH_MAX, "%s/%s/%s", p, DB_USER_PATH, DB_FILENAME);

  STRNDUP(p, b, PATH_MAX);
  FREE(b);

  return p;
}
Example #4
0
File: db.c Project: AdUser/xa-tags
static char *
_db_get_fts_query(const search_t *search)
{
  char *query = NULL;
  size_t i = 0;

  if (search->substr.items != 0)
    {
      CALLOC(query, search->substr.len, sizeof(char));
      memcpy(query, search->substr.buf, search->substr.len);
      for (i = 0; i < search->substr.len - 1; i++)
        if (query[i] == '\0')
          query[i] = ' ';
    }
  else
    {
      STRNDUP(query, "*", 2);
    }

  return query;
}
Example #5
0
PUBLIC DBnamescheme *
DBMakeNamescheme(char const *fmt, ...)
{
    va_list ap;
    int i, j, k, n, pass, ncspecs, done, saved_narrefs;
    DBnamescheme *rv = 0;
    DBfile *dbfile = 0;
    char const *relpath = 0;

    /* We have nothing to do for a null or empty format string */
    if (fmt == 0 || *fmt == '\0')
        return 0;

    /* Start by allocating an empty name scheme */
    rv = DBAllocNamescheme();

    // set the delimeter character
    n = 0;
    while (fmt[n] != '\0')
    {
        if (fmt[n] == '%' && fmt[n+1] != '%')
            break;
        n++;
    }
    if (fmt[n] == '%') // have at least one conversion spec
        rv->delim = fmt[0];
    else
        rv->delim = '\0';
    
    /* compute length up to max of 4096 of initial segment of fmt representing
       the printf-style format string. */
    n = 1;
    while (n < 4096 && fmt[n] != '\0' && fmt[n] != rv->delim)
        n++;
    if (n == 4096) /* we pick arb. upper bound in length of 4096 */
    {
        DBFreeNamescheme(rv);
        return 0;
    }

    /* grab just the part of fmt that is the printf-style format string */
    rv->fmt = STRNDUP(&fmt[1],n-1);
    rv->fmtlen = n-1;

    /* In 2 passes, count conversion specs. and then setup pointers to each */ 
    for (pass = 0; pass < 2; pass++)
    {
        if (pass == 1)
        {
            rv->fmtptrs = (const char **) calloc(rv->ncspecs+1, sizeof(char*));
            rv->ncspecs = 0;
        }
        for (i = 0; i < rv->fmtlen-1; i++)
        {
            if (rv->fmt[i] == '%' && 
                rv->fmt[i+1] != '%')
            {
                if (pass == 1)
                    rv->fmtptrs[rv->ncspecs] = &(rv->fmt[i]);
                rv->ncspecs++;
            }
        }
    }
    rv->fmtptrs[rv->ncspecs] = &(rv->fmt[n+1]);

    /* If there are no conversion specs., we have nothing to do */
    /* However, in this case, assume the first char is a real char. */
    if (rv->ncspecs == 0)
    {
        free(rv->fmt);
        rv->fmt = STRNDUP(&fmt[0],n);
        rv->fmtlen = n;
        return rv;
    }

    /* Make a pass through rest of fmt string to count array refs in the
       expression substrings. */
    i = n+1;
    while (i < 4096 && fmt[i] != '\0')
    {
        if (fmt[i] == '$' || fmt[i] == '#')
            rv->narrefs++;
        i++;
    }
    if (i == 4096)
    {
        DBFreeNamescheme(rv);
        return 0;
    }

    /* allocate various arrays needed by the naming scheme */
    rv->exprstrs = (char **) calloc(rv->ncspecs, sizeof(char*));
    if (rv->narrefs > 0)
    {
        void *dummy;

        rv->arrnames = (char **) calloc(rv->narrefs, sizeof(char*));
        rv->arrvals  = (void **) calloc(rv->narrefs, sizeof(void*));
        rv->arrsizes =   (int *) calloc(rv->narrefs, sizeof(int));

        /* If we have non-zero ext. array references, then we may have the case of
           '0, DBfile*'. So, check for that now */
        va_start(ap, fmt);
        dummy = va_arg(ap, void *);
        if (dummy == 0)
        {
            dbfile = va_arg(ap, DBfile *);
            relpath = va_arg(ap, char const *);
            rv->arralloc = 1;
        }
Example #6
0
PUBLIC DBnamescheme *
DBMakeNamescheme(const char *fmt, ...)
{
    va_list ap;
    int i, j, k, n, pass, ncspecs, done;
    DBnamescheme *rv = 0;

    /* We have nothing to do for a null or empty format string */
    if (fmt == 0 || *fmt == '\0')
        return 0;

    /* Start by allocating an empty name scheme */
    rv = DBAllocNamescheme();
    
    /* set the delimeter character */
    rv->delim = fmt[0];

    /* compute length up to max of 4096 of initial segment of fmt representing
       the printf-style format string. */
    n = 1;
    while (n < 4096 && fmt[n] != '\0' && fmt[n] != rv->delim)
        n++;
    if (n == 4096) /* we pick arb. upper bound in length of 4096 */
    {
        DBFreeNamescheme(rv);
        return 0;
    }

    /* grab just the part of fmt that is the printf-style format string */
    rv->fmt = STRNDUP(&fmt[1],n-1);
    rv->fmtlen = n-1;

    /* In 2 passes, count conversion specs. and then setup pointers to each */ 
    for (pass = 0; pass < 2; pass++)
    {
        if (pass == 1)
        {
            rv->fmtptrs = (const char **) calloc(rv->ncspecs+1, sizeof(char*));
            rv->ncspecs = 0;
        }
        for (i = 0; i < rv->fmtlen-1; i++)
        {
            if (rv->fmt[i] == '%' && 
                rv->fmt[i+1] != '%')
            {
                if (pass == 1)
                    rv->fmtptrs[rv->ncspecs] = &(rv->fmt[i]);
                rv->ncspecs++;
            }
        }
    }
    rv->fmtptrs[rv->ncspecs] = &(rv->fmt[n+1]);

    /* If there are no conversion specs., we have nothing to do */
    if (rv->ncspecs == 0)
        return rv;

    /* Make a pass through rest of fmt string to count array refs in the
       expression substrings. */
    i = n+1;
    while (i < 4096 && fmt[i] != '\0')
    {
        if (fmt[i] == '$' || fmt[i] == '#')
            rv->narrefs++;
        i++;
    }
    if (i == 4096)
    {
        DBFreeNamescheme(rv);
        return 0;
    }

    /* allocate various arrays needed by the naming scheme */
    rv->exprstrs = (char **) calloc(rv->ncspecs, sizeof(char*));
    if (rv->narrefs > 0)
    {
        rv->arrnames = (char **) calloc(rv->narrefs, sizeof(char*));
        rv->arrvals  = (const int **) calloc(rv->narrefs, sizeof(int*));
    }

    /* Ok, now go through rest of fmt string a second time and grab each
       expression that goes with each conversion spec. Also, handle array refs */
    i = n+1;
    rv->narrefs = 0;
    ncspecs = 0;
    va_start(ap, fmt);
    done = 0;
    while (!done)
    {
        if (fmt[i] == '$' || fmt[i] == '#')
        {
            for (j = 1; fmt[i+j] != '['; j++)
                ;
            for (k = 0; k < rv->narrefs; k++)
            {
                if (strncmp(&fmt[i+1],rv->arrnames[k],j-1) == 0)
                    break;
            }
            if (k == rv->narrefs)
            {
                rv->arrnames[k] = STRNDUP(&fmt[i+1], j-1);
                rv->arrvals[k] = va_arg(ap, const int *);
                rv->narrefs++;
            }
        }
        else if (fmt[i] == rv->delim || fmt[i] == '\0')
Example #7
0
                ;
            for (k = 0; k < rv->narrefs; k++)
            {
                if (strncmp(&fmt[i+1],rv->arrnames[k],j-1) == 0)
                    break;
            }
            if (k == rv->narrefs)
            {
                rv->arrnames[k] = STRNDUP(&fmt[i+1], j-1);
                rv->arrvals[k] = va_arg(ap, const int *);
                rv->narrefs++;
            }
        }
        else if (fmt[i] == rv->delim || fmt[i] == '\0')
        {
            rv->exprstrs[ncspecs] = STRNDUP(&fmt[n+1],i-(n+1));
            ncspecs++;
            if (fmt[i] == '\0' ||
                (fmt[i] == rv->delim && fmt[i] == '\0'))
                done = 1;
            n = i;
        }
        i++;
    }
    va_end(ap);

    return rv;
}

PUBLIC const char *
DBGetName(DBnamescheme *ns, int natnum)
Example #8
0
boolean_t iosocket_wait(io_desc *iod, int4 timepar)
{
	struct 	timeval  	utimeout;
	ABS_TIME		cur_time, end_time;
	struct 	sockaddr_storage    	peer;           /* socket address + port */
	fd_set    		tcp_fd;
	d_socket_struct 	*dsocketptr;
	socket_struct   	*socketptr, *newsocketptr;
	socket_interrupt	*sockintr;
	char            	*errptr;
	int4            	errlen, ii, msec_timeout;
	int			rv, max_fd, len;
	GTM_SOCKLEN_TYPE	size;
	boolean_t		zint_restart;
	mv_stent		*mv_zintdev;
	int			retry_num;
	struct sockaddr		*peer_sa_ptr;
	char			port_buffer[NI_MAXSERV], ipaddr[SA_MAXLEN + 1];
	int			errcode;

	/* check for validity */
	assert(iod->type == gtmsocket);
	dsocketptr = (d_socket_struct *)iod->dev_sp;
	sockintr = &dsocketptr->sock_save_state;
	peer_sa_ptr = ((struct sockaddr *)(&peer));

	/* Check for restart */
	if (!dsocketptr->mupintr)
		/* Simple path, no worries*/
		zint_restart = FALSE;
	else
	{       /* We have a pending wait restart of some sort - check we aren't recursing on this device */
		if (sockwhich_invalid == sockintr->who_saved)
			GTMASSERT;	/* Interrupt should never have an invalid save state */
		if (dollar_zininterrupt)
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
		if (sockwhich_wait != sockintr->who_saved)
			GTMASSERT;      /* ZINTRECURSEIO should have caught */
		DBGSOCK((stdout, "socwait: *#*#*#*#*#*#*#  Restarted interrupted wait\n"));
		mv_zintdev = io_find_mvstent(iod, FALSE);
		if (mv_zintdev)
		{
			if (sockintr->end_time_valid)
				/* Restore end_time for timeout */
				end_time = sockintr->end_time;

			/* Done with this mv_stent. Pop it off if we can, else mark it inactive. */
			if (mv_chain == mv_zintdev)
				POP_MV_STENT();         /* pop if top of stack */
			else
			{       /* else mark it unused */
				mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE;
				mv_zintdev->mv_st_cont.mvs_zintdev.io_ptr = NULL;
			}
			zint_restart = TRUE;
			DBGSOCK((stdout, "socwait: mv_stent found - endtime: %d/%d\n", end_time.at_sec, end_time.at_usec));
		} else
			DBGSOCK((stdout, "socwait: no mv_stent found !!\n"));
		dsocketptr->mupintr = FALSE;
		sockintr->who_saved = sockwhich_invalid;
	}
	/* check for events */
	FD_ZERO(&tcp_fd);
	while (TRUE)
	{
		max_fd = 0;
		for (ii = 0; ii < dsocketptr->n_socket; ii++)
		{
			socketptr = dsocketptr->socket[ii];
			if ((socket_listening == socketptr->state) || (socket_connected == socketptr->state))
			{
				FD_SET(socketptr->sd, &tcp_fd);
				max_fd = MAX(max_fd, socketptr->sd);
			}
		}
		utimeout.tv_sec = timepar;
		utimeout.tv_usec = 0;
		msec_timeout = timeout2msec(timepar);
		sys_get_curr_time(&cur_time);
		if (!zint_restart || !sockintr->end_time_valid)
			add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
		else
		{       /* end_time taken from restart data. Compute what msec_timeout should be so timeout timer
					   gets set correctly below.
			*/
			DBGSOCK((stdout, "socwait: Taking timeout end time from wait restart data\n"));
			cur_time = sub_abs_time(&end_time, &cur_time);
			if (0 > cur_time.at_sec)
			{
				msec_timeout = -1;
				utimeout.tv_sec = 0;
				utimeout.tv_usec = 0;
			} else
			{
				msec_timeout = (int4)(cur_time.at_sec * 1000 + cur_time.at_usec / 1000);
				utimeout.tv_sec = cur_time.at_sec;
				utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
			}
		}
		sockintr->end_time_valid = FALSE;
		for ( ; ; )
		{
			rv = select(max_fd + 1, (void *)&tcp_fd, (void *)0, (void *)0,
				    (timepar == NO_M_TIMEOUT ? (struct timeval *)0 : &utimeout));
			if (0 > rv && EINTR == errno)
			{
				if (0 != outofband)
				{
					DBGSOCK((stdout, "socwait: outofband interrupt received (%d) -- "
						 "queueing mv_stent for wait intr\n", outofband));
					PUSH_MV_STENT(MVST_ZINTDEV);
					mv_chain->mv_st_cont.mvs_zintdev.io_ptr = iod;
					mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = FALSE;
					sockintr->who_saved = sockwhich_wait;
					sockintr->end_time = end_time;
					sockintr->end_time_valid = TRUE;
					dsocketptr->mupintr = TRUE;
					socketus_interruptus++;
					DBGSOCK((stdout, "socwait: mv_stent queued - endtime: %d/%d  interrupts: %d\n",
						 end_time.at_sec, end_time.at_usec, socketus_interruptus));
					outofband_action(FALSE);
					GTMASSERT;      /* Should *never* return from outofband_action */
					return FALSE;   /* For the compiler.. */
				}
				sys_get_curr_time(&cur_time);
				cur_time = sub_abs_time(&end_time, &cur_time);
				if (0 > cur_time.at_sec)
				{
					rv = 0;		/* time out */
					break;
				}
				utimeout.tv_sec = cur_time.at_sec;
				utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
			} else
				break;	/* either other error or done */
		}
		if (rv == 0)
		{
			iod->dollar.key[0] = '\0';
			return FALSE;
		} else  if (rv < 0)
		{
			errptr = (char *)STRERROR(errno);
			errlen = STRLEN(errptr);
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr);
			return FALSE;
		}
		/* find out which socket is ready */
		for (ii = 0; ii < dsocketptr->n_socket; ii++)
		{
			socketptr = dsocketptr->socket[ii];
			if (0 != FD_ISSET(socketptr->sd, &tcp_fd))
				break;
		}
		assert(ii < dsocketptr->n_socket);
		if (socket_listening == socketptr->state)
		{
			if (gtm_max_sockets <= dsocketptr->n_socket)
			{
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets);
				return FALSE;
			}

			size = SIZEOF(struct sockaddr_storage);
			rv = tcp_routines.aa_accept(socketptr->sd, peer_sa_ptr, &size);
			if (-1 == rv)
			{
#				ifdef __hpux
				if (ENOBUFS == errno)
					continue;	/* On HP-UX, ENOBUFS may indicate a transient condition; retry */
#				endif
				errptr = (char *)STRERROR(errno);
				errlen = STRLEN(errptr);
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr);
				return FALSE;
			}
			SOCKET_DUP(socketptr, newsocketptr);
			newsocketptr->sd = rv;
			SOCKET_ADDR_COPY(newsocketptr->remote, peer_sa_ptr, size);
			/* translate internal address to numeric ip address */
			GETNAMEINFO(peer_sa_ptr, size, ipaddr, SA_MAXLEN, NULL, 0, NI_NUMERICHOST, errcode);
			if (0 != errcode)
			{
				SOCKET_FREE(newsocketptr);
				RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
				return FALSE;
			}
			if (NULL != newsocketptr->remote.saddr_ip)
				free(newsocketptr->remote.saddr_ip);
			STRNDUP(ipaddr, SA_MAXLEN, newsocketptr->remote.saddr_ip);
			/* translate internal address to port number*/
			GETNAMEINFO(peer_sa_ptr, size, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode);
			if (0 != errcode)
			{
				SOCKET_FREE(newsocketptr);
				RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
				return FALSE;
			}
			newsocketptr->remote.port = ATOI(port_buffer);
			newsocketptr->state = socket_connected;
			newsocketptr->passive = FALSE;
			newsocketptr->first_read = newsocketptr->first_write = TRUE;
			/* put the new-born socket to the list and create a handle for it */
			iosocket_handle(newsocketptr->handle, &newsocketptr->handle_len, TRUE, dsocketptr);
			dsocketptr->socket[dsocketptr->n_socket++] = newsocketptr;
			dsocketptr->current_socket = dsocketptr->n_socket - 1;
			len = SIZEOF(CONNECTED) - 1;
			memcpy(&iod->dollar.key[0], CONNECTED, len);
			iod->dollar.key[len++] = '|';
			memcpy(&iod->dollar.key[len], newsocketptr->handle, newsocketptr->handle_len);
			len += newsocketptr->handle_len;
			iod->dollar.key[len++] = '|';
			strncpy(&iod->dollar.key[len], newsocketptr->remote.saddr_ip, DD_BUFLEN - 1 - len);
			iod->dollar.key[DD_BUFLEN-1] = '\0';		/* In case we fill the buffer */
		} else
		{
			assert(socket_connected == socketptr->state);
			dsocketptr->current_socket = ii;
			len = SIZEOF(READ) - 1;
			memcpy(&iod->dollar.key[0], READ, len);
			iod->dollar.key[len++] = '|';
			memcpy(&iod->dollar.key[len], socketptr->handle, socketptr->handle_len);
			len += socketptr->handle_len;
			iod->dollar.key[len++] = '|';
			if (NULL != socketptr->remote.saddr_ip)
			{
				strncpy(&iod->dollar.key[len], socketptr->remote.saddr_ip, DD_BUFLEN - 1 - len);
				iod->dollar.key[DD_BUFLEN-1] = '\0';
			} else
				iod->dollar.key[len] = '\0';
		}
		break;
	}
Example #9
0
/** Helper function: read the next token from *s, advance *s to the end of the
 * token, and return the parsed token.  Parse *<b>s</b> according to the list
 * of tokens in <b>table</b>.
 */
directory_token_t *
get_next_token(memarea_t *area,
               const char **s, const char *eos, token_rule_t *table)
{
  /** Reject any object at least this big; it is probably an overflow, an
   * attack, a bug, or some other nonsense. */
#define MAX_UNPARSED_OBJECT_SIZE (128*1024)
  /** Reject any line at least this big; it is probably an overflow, an
   * attack, a bug, or some other nonsense. */
#define MAX_LINE_LENGTH (128*1024)

  const char *next, *eol, *obstart;
  size_t obname_len;
  int i;
  directory_token_t *tok;
  obj_syntax o_syn = NO_OBJ;
  char ebuf[128];
  const char *kwd = "";

  tor_assert(area);
  tok = ALLOC_ZERO(sizeof(directory_token_t));
  tok->tp = ERR_;

  /* Set *s to first token, eol to end-of-line, next to after first token */
  *s = eat_whitespace_eos(*s, eos); /* eat multi-line whitespace */
  tor_assert(eos >= *s);
  eol = memchr(*s, '\n', eos-*s);
  if (!eol)
    eol = eos;
  if (eol - *s > MAX_LINE_LENGTH) {
    RET_ERR("Line far too long");
  }

  next = find_whitespace_eos(*s, eol);

  if (!strcmp_len(*s, "opt", next-*s)) {
    /* Skip past an "opt" at the start of the line. */
    *s = eat_whitespace_eos_no_nl(next, eol);
    next = find_whitespace_eos(*s, eol);
  } else if (*s == eos) {  /* If no "opt", and end-of-line, line is invalid */
    RET_ERR("Unexpected EOF");
  }

  /* Search the table for the appropriate entry.  (I tried a binary search
   * instead, but it wasn't any faster.) */
  for (i = 0; table[i].t ; ++i) {
    if (!strcmp_len(*s, table[i].t, next-*s)) {
      /* We've found the keyword. */
      kwd = table[i].t;
      tok->tp = table[i].v;
      o_syn = table[i].os;
      *s = eat_whitespace_eos_no_nl(next, eol);
      /* We go ahead whether there are arguments or not, so that tok->args is
       * always set if we want arguments. */
      if (table[i].concat_args) {
        /* The keyword takes the line as a single argument */
        tok->args = ALLOC(sizeof(char*));
        tok->args[0] = STRNDUP(*s,eol-*s); /* Grab everything on line */
        tok->n_args = 1;
      } else {
        /* This keyword takes multiple arguments. */
        if (get_token_arguments(area, tok, *s, eol)<0) {
          tor_snprintf(ebuf, sizeof(ebuf),"Far too many arguments to %s", kwd);
          RET_ERR(ebuf);
        }
        *s = eol;
      }
      if (tok->n_args < table[i].min_args) {
        tor_snprintf(ebuf, sizeof(ebuf), "Too few arguments to %s", kwd);
        RET_ERR(ebuf);
      } else if (tok->n_args > table[i].max_args) {
        tor_snprintf(ebuf, sizeof(ebuf), "Too many arguments to %s", kwd);
        RET_ERR(ebuf);
      }
      break;
    }
  }

  if (tok->tp == ERR_) {
    /* No keyword matched; call it an "K_opt" or "A_unrecognized" */
    if (**s == '@')
      tok->tp = A_UNKNOWN_;
    else
      tok->tp = K_OPT;
    tok->args = ALLOC(sizeof(char*));
    tok->args[0] = STRNDUP(*s, eol-*s);
    tok->n_args = 1;
    o_syn = OBJ_OK;
  }

  /* Check whether there's an object present */
  *s = eat_whitespace_eos(eol, eos);  /* Scan from end of first line */
  tor_assert(eos >= *s);
  eol = memchr(*s, '\n', eos-*s);
  if (!eol || eol-*s<11 || strcmpstart(*s, "-----BEGIN ")) /* No object. */
    goto check_object;

  obstart = *s; /* Set obstart to start of object spec */
  if (*s+16 >= eol || memchr(*s+11,'\0',eol-*s-16) || /* no short lines, */
      strcmp_len(eol-5, "-----", 5) ||           /* nuls or invalid endings */
      (eol-*s) > MAX_UNPARSED_OBJECT_SIZE) {     /* name too long */
    RET_ERR("Malformed object: bad begin line");
  }
  tok->object_type = STRNDUP(*s+11, eol-*s-16);
  obname_len = eol-*s-16; /* store objname length here to avoid a strlen() */
  *s = eol+1;    /* Set *s to possible start of object data (could be eos) */

  /* Go to the end of the object */
  next = tor_memstr(*s, eos-*s, "-----END ");
  if (!next) {
    RET_ERR("Malformed object: missing object end line");
  }
  tor_assert(eos >= next);
  eol = memchr(next, '\n', eos-next);
  if (!eol)  /* end-of-line marker, or eos if there's no '\n' */
    eol = eos;
  /* Validate the ending tag, which should be 9 + NAME + 5 + eol */
  if ((size_t)(eol-next) != 9+obname_len+5 ||
      strcmp_len(next+9, tok->object_type, obname_len) ||
      strcmp_len(eol-5, "-----", 5)) {
    tor_snprintf(ebuf, sizeof(ebuf), "Malformed object: mismatched end tag %s",
             tok->object_type);
    ebuf[sizeof(ebuf)-1] = '\0';
    RET_ERR(ebuf);
  }
  if (next - *s > MAX_UNPARSED_OBJECT_SIZE)
    RET_ERR("Couldn't parse object: missing footer or object much too big.");

  if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */
    tok->key = crypto_pk_new();
    if (crypto_pk_read_public_key_from_string(tok->key, obstart, eol-obstart))
      RET_ERR("Couldn't parse public key.");
  } else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */
    tok->key = crypto_pk_new();
    if (crypto_pk_read_private_key_from_string(tok->key, obstart, eol-obstart))
      RET_ERR("Couldn't parse private key.");
  } else { /* If it's something else, try to base64-decode it */
    int r;
    tok->object_body = ALLOC(next-*s); /* really, this is too much RAM. */
    r = base64_decode(tok->object_body, next-*s, *s, next-*s);
    if (r<0)
      RET_ERR("Malformed object: bad base64-encoded data");
    tok->object_size = r;
  }
  *s = eol;

 check_object:
  tok = token_check_object(area, kwd, tok, o_syn);

 done_tokenizing:
  return tok;

#undef RET_ERR
#undef ALLOC
#undef ALLOC_ZERO
#undef STRDUP
#undef STRNDUP
}