Exemplo n.º 1
0
 static bool _lookup(Node<T> const* node, T v) {
     if (node == nullptr) {
         return false;
     } else if (node->value == v) {
         return true;
     } else if (v < node->value) {
         return _lookup(node->left, v);
     } else {
         return _lookup(node->right, v);
     }
 }
Exemplo n.º 2
0
int
mu_sieve_require_comparator (mu_sieve_machine_t mach, const char *name)
{
  sieve_comparator_record_t *reg = _lookup (mach->comp_list, name);
  if (!reg)
    {
      if (!(mu_sieve_load_ext (mach, name) == 0
	    && (reg = _lookup (mach->comp_list, name)) != NULL))
	return 1;
    }

  reg->required = 1;
  return 0;
}
Exemplo n.º 3
0
static integer e5(void)
{
  integer result;
  char* name;
  {
    if (scan_test(NULL, SCAN_P_ID, NULL))
    {
      scan_test(NULL, SCAN_P_ID, &e5_stop);
      name = SCAN_CAST->id;
      scan_();
      _lookup(name, result);
    }
    else
    if (scan_test(NULL, SCAN_P_INTEGER, NULL))
    {
      scan_test(NULL, SCAN_P_INTEGER, &e5_stop);
      result = SCAN_CAST->data.i;
      scan_();
    }
    else
    if (scan_test(NULL, RDP_T_40 /* ( */, NULL))
    {
      scan_test(NULL, RDP_T_40 /* ( */, &e5_stop);
      scan_();
      result = e1();
      scan_test(NULL, RDP_T_41 /* ) */, &e5_stop);
      scan_();
    }
    else
      scan_test_set(NULL, &e5_first, &e5_stop)    ;
    scan_test_set(NULL, &e5_stop, &e5_stop);
   }
  return result;
}
Exemplo n.º 4
0
struct slice *btree_get(struct btree *btree, struct slice *sk)
{
	uint32_t offset;
	uint32_t len;
	char *data;
	struct slice *sv;
	
	sv = calloc(1, sizeof(*sv));

	offset = _lookup(btree, btree->top, sk->data);
	if (offset == 0)
		return NULL;

	lseek(btree->db_fd, offset, SEEK_SET);

	if (read(btree->db_fd, &len, sizeof(int)) != sizeof(int))
		return NULL;

	sv->len = len;
	data = malloc(sv->len + 1);
	memset(data, 0, sv->len + 1);

	if (read(btree->db_fd, data, sv->len) != sv->len) {
		free(data);
		free(sv);

		return NULL;
	}
	sv->data = data;

	return sv;
}
/*  
    def lookup1(self, required, provided, name=u'', default=None):
        cache = self._getcache(provided, name)
        result = cache.get(required, _not_in_mapping)
        if result is _not_in_mapping:
            return self.lookup((required, ), provided, name, default)

        if result is None:
            return default

        return result
*/
static PyObject *
_lookup1(lookup *self, 
        PyObject *required, PyObject *provided, PyObject *name, 
        PyObject *default_)
{
  PyObject *result, *cache;

  cache = _getcache(self, provided, name);
  if (cache == NULL)
    return NULL;

  result = PyDict_GetItem(cache, required);
  if (result == NULL)
    {
      PyObject *tup;

      tup = PyTuple_New(1);
      if (tup == NULL)
        return NULL;
      Py_INCREF(required);
      PyTuple_SET_ITEM(tup, 0, required);
      result = _lookup(self, tup, provided, name, default_);
      Py_DECREF(tup);
    }
  else
    Py_INCREF(result);

  return result;
}
Exemplo n.º 6
0
Status ViewCatalog::modifyView(OperationContext* opCtx,
                               const NamespaceString& viewName,
                               const NamespaceString& viewOn,
                               const BSONArray& pipeline) {
    stdx::lock_guard<stdx::mutex> lk(_mutex);

    if (viewName.db() != viewOn.db())
        return Status(ErrorCodes::BadValue,
                      "View must be created on a view or collection in the same database");

    auto viewPtr = _lookup(lk, opCtx, viewName.ns());
    if (!viewPtr)
        return Status(ErrorCodes::NamespaceNotFound,
                      str::stream() << "cannot modify missing view " << viewName.ns());

    if (!NamespaceString::validCollectionName(viewOn.coll()))
        return Status(ErrorCodes::InvalidNamespace,
                      str::stream() << "invalid name for 'viewOn': " << viewOn.coll());

    ViewDefinition savedDefinition = *viewPtr;
    opCtx->recoveryUnit()->onRollback([this, viewName, savedDefinition]() {
        this->_viewMap[viewName.ns()] = std::make_shared<ViewDefinition>(savedDefinition);
    });

    return _createOrUpdateView(lk,
                               opCtx,
                               viewName,
                               viewOn,
                               pipeline,
                               CollatorInterface::cloneCollator(savedDefinition.defaultCollator()));
}
Exemplo n.º 7
0
Status ViewCatalog::createView(OperationContext* opCtx,
                               const NamespaceString& viewName,
                               const NamespaceString& viewOn,
                               const BSONArray& pipeline,
                               const BSONObj& collation) {
    stdx::lock_guard<stdx::mutex> lk(_mutex);

    if (viewName.db() != viewOn.db())
        return Status(ErrorCodes::BadValue,
                      "View must be created on a view or collection in the same database");

    if (_lookup(lk, opCtx, StringData(viewName.ns())))
        return Status(ErrorCodes::NamespaceExists, "Namespace already exists");

    if (!NamespaceString::validCollectionName(viewOn.coll()))
        return Status(ErrorCodes::InvalidNamespace,
                      str::stream() << "invalid name for 'viewOn': " << viewOn.coll());

    if (viewName.isSystem())
        return Status(
            ErrorCodes::InvalidNamespace,
            "View name cannot start with 'system.', which is reserved for system namespaces");

    auto collator = parseCollator(opCtx, collation);
    if (!collator.isOK())
        return collator.getStatus();

    return _createOrUpdateView(
        lk, opCtx, viewName, viewOn, pipeline, std::move(collator.getValue()));
}
Exemplo n.º 8
0
Status ViewCatalog::dropView(OperationContext* opCtx, const NamespaceString& viewName) {
    stdx::lock_guard<stdx::mutex> lk(_mutex);
    _requireValidCatalog(lk, opCtx);

    // Save a copy of the view definition in case we need to roll back.
    auto viewPtr = _lookup(lk, opCtx, viewName.ns());
    if (!viewPtr) {
        return {ErrorCodes::NamespaceNotFound,
                str::stream() << "cannot drop missing view: " << viewName.ns()};
    }

    ViewDefinition savedDefinition = *viewPtr;

    invariant(_valid.load());
    _durable->remove(opCtx, viewName);
    _viewGraph.remove(savedDefinition.name());
    _viewMap.erase(viewName.ns());
    opCtx->recoveryUnit()->onRollback([this, viewName, savedDefinition]() {
        this->_viewGraphNeedsRefresh = true;
        this->_viewMap[viewName.ns()] = std::make_shared<ViewDefinition>(savedDefinition);
    });

    // We may get invalidated, but we're exclusively locked, so the change must be ours.
    opCtx->recoveryUnit()->onCommit(
        [this](boost::optional<Timestamp>) { this->_valid.store(true); });
    return Status::OK();
}
Exemplo n.º 9
0
Symbol *SymbolTable::lookup(const char *name)
{
   int	offset;

   offset = _lookup(name);
   return (offset == -1) ? ((Symbol *)0) : syms[offset];
}
Exemplo n.º 10
0
int SymbolTable::remove(const char *name)
{
   int offset = _lookup(name);

   if (offset == -1)
      return -1;
   _remove(offset, 1);
   return 0;
}
Exemplo n.º 11
0
mu_sieve_comparator_t 
mu_sieve_comparator_lookup (mu_sieve_machine_t mach, const char *name, 
                            int matchtype)
{
  sieve_comparator_record_t *reg = _lookup (mach->comp_list, name);
  if (reg && reg->comp[matchtype])
    return reg->comp[matchtype];
  return NULL;
}
Exemplo n.º 12
0
int SymbolTable::remove(Symbol *sym)
{
   int	offset;

   offset = _lookup(sym->name());
   if (offset == -1  ||  syms[offset] != sym)
      return -1;

   _remove(offset, 0);
   return 0;
}
static PyObject *
lookup_lookup(lookup *self, PyObject *args, PyObject *kwds)
{
  static char *kwlist[] = {"required", "provided", "name", "default", NULL};
  PyObject *required, *provided, *name=NULL, *default_=NULL;

  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
                                    &required, &provided, &name, &default_))
    return NULL;

  return _lookup(self, required, provided, name, default_);
}
/*
    def lookup1(self, required, provided, name=u'', default=None):
        cache = self._getcache(provided, name)
        result = cache.get(required, _not_in_mapping)
        if result is _not_in_mapping:
            return self.lookup((required, ), provided, name, default)

        if result is None:
            return default

        return result
*/
static PyObject *
_lookup1(lookup *self,
        PyObject *required, PyObject *provided, PyObject *name,
        PyObject *default_)
{
  PyObject *result, *cache;

#ifdef PY3K
  if ( name && !PyUnicode_Check(name) )
#else
  if ( name && !PyString_Check(name) && !PyUnicode_Check(name) )
#endif
  {
    PyErr_SetString(PyExc_ValueError,
                    "name is not a string or unicode");
    return NULL;
  }

  cache = _getcache(self, provided, name);
  if (cache == NULL)
    return NULL;

  result = PyDict_GetItem(cache, required);
  if (result == NULL)
    {
      PyObject *tup;

      tup = PyTuple_New(1);
      if (tup == NULL)
        return NULL;
      Py_INCREF(required);
      PyTuple_SET_ITEM(tup, 0, required);
      result = _lookup(self, tup, provided, name, default_);
      Py_DECREF(tup);
    }
  else
    {
      if (result == Py_None && default_ != NULL)
        {
          result = default_;
        }
      Py_INCREF(result);
    }

  return result;
}
Exemplo n.º 15
0
Status ViewCatalog::_validateCollation(WithLock lk,
                                       OperationContext* opCtx,
                                       const ViewDefinition& view,
                                       const std::vector<NamespaceString>& refs) {
    for (auto&& potentialViewNss : refs) {
        auto otherView = _lookup(lk, opCtx, potentialViewNss.ns());
        if (otherView &&
            !CollatorInterface::collatorsMatch(view.defaultCollator(),
                                               otherView->defaultCollator())) {
            return {ErrorCodes::OptionNotSupportedOnView,
                    str::stream() << "View " << view.name().toString()
                                  << " has conflicting collation with view "
                                  << otherView->name().toString()};
        }
    }
    return Status::OK();
}
static const SkMemberInfo* _lookup(int lookup, const char** matchPtr) {
    int count = gInfoCounts[lookup];
    const SkMemberInfo* info = gInfoTables[lookup];
    if (info->fType == SkType_BaseClassInfo) {
        int baseTypeLookup = info->fOffset;
        const SkMemberInfo* result = _lookup(baseTypeLookup, matchPtr);
        if (result != NULL)
            return result;
        if (--count == 0)
            return NULL;
        info++;
    }
    SkASSERT(info->fType != SkType_BaseClassInfo);
    const char* match = *matchPtr;
    const char* strings = gInfoNames[lookup];
    int index = _searchByName(&info->fName, count, strings, match);
    if (index < 0)
        return NULL;
    return &info[index];
}
Exemplo n.º 17
0
// We've just read an '&'; look for an entity reference
// name, and if found, return translated char.
// if there is a complete entity name but it isn't known,
// back up to just past the '&' and return '&'.
// If the entity can't be completed in the current buffer, back up
// to the '&' and return -1.
static int
ampersand(TokenSource* ts)
{
	int	savei;
	int	c;
	int	fnd;
	int	ans;
	int	v;
	int	k;
	Rune	buf[25];

	savei = ts->i;
	c = getchar(ts);
	fnd = 0;
	ans = -1;
	if(c == '#') {
		c = getchar(ts);
		v = 0;
		if(c == 'X' || c == 'x')
			for(c = getchar(ts); c < 256; c = getchar(ts))
				if(c >= '0' && c <= '9')
					v = v*16+c-'0';
				else if(c >= 'A' && c<= 'F')
					v = v*16+c-'A'+10;
				else if(c >= 'a' && c <= 'f')
					v = v*16+c-'a'+10;
				else
					break;
		else
			while(c >= 0) {
				if(!(c < 256 && isdigit(c)))
					break;
				v = v*10 + c - 48;
				c = getchar(ts);
			}
		if(c >= 0) {
			if(!(c == ';' || c == '\n' || c == '\r'))
				ungetchar(ts, c);
			c = v;
			if(c == 160)
				c = 160;
			if(c >= Winstart && c <= Winend) {
				c = winchars[c - Winstart];
			}
			ans = c;
			fnd = 1;
		}
	}
	else if(c < 256 && isalpha(c)) {
		buf[0] = c;
		k = 1;
		while(1) {
			c = getchar(ts);
			if(c < 0)
				break;
			if(c < 256 && (isalpha(c) || isdigit(c))) {
				if(k < nelem(buf)-1)
					buf[k++] = c;
			}
			else {
				if(!(c == ';' || c == '\n' || c == '\r'))
					ungetchar(ts, c);
				break;
			}
		}
		if(c >= 256 || c != '=' && !(isalpha(c) || isdigit(c)))
			fnd = _lookup(chartab, NCHARTAB, buf, k, &ans);
	}
	if(!fnd) {
		backup(ts, savei);
		ans = '&';
	}
	return ans;
}
Exemplo n.º 18
0
// read-only lookup
LSym*
linkrlookup(Link *ctxt, char *name, int v)
{
	return _lookup(ctxt, name, v, 0);
}
Exemplo n.º 19
0
StatusWith<ResolvedView> ViewCatalog::resolveView(OperationContext* opCtx,
                                                  const NamespaceString& nss) {
    stdx::unique_lock<stdx::mutex> lock(_mutex);

    // Keep looping until the resolution completes. If the catalog is invalidated during the
    // resolution, we start over from the beginning.
    while (true) {
        // Points to the name of the most resolved namespace.
        const NamespaceString* resolvedNss = &nss;

        // Holds the combination of all the resolved views.
        std::vector<BSONObj> resolvedPipeline;

        // If the catalog has not been tampered with, all views seen during the resolution will have
        // the same collation. As an optimization, we fill out the collation spec only once.
        boost::optional<BSONObj> collation;

        // The last seen view definition, which owns the NamespaceString pointed to by
        // 'resolvedNss'.
        std::shared_ptr<ViewDefinition> lastViewDefinition;

        int depth = 0;
        for (; depth < ViewGraph::kMaxViewDepth; depth++) {
            // If the catalog has been invalidated, bail and restart.
            if (!_valid.load()) {
                uassertStatusOK(_reloadIfNeeded(lock, opCtx));
                break;
            }

            auto view = _lookup(lock, opCtx, resolvedNss->ns());
            if (!view) {
                // Return error status if pipeline is too large.
                int pipelineSize = 0;
                for (auto obj : resolvedPipeline) {
                    pipelineSize += obj.objsize();
                }
                if (pipelineSize > ViewGraph::kMaxViewPipelineSizeBytes) {
                    return {ErrorCodes::ViewPipelineMaxSizeExceeded,
                            str::stream() << "View pipeline exceeds maximum size; maximum size is "
                                          << ViewGraph::kMaxViewPipelineSizeBytes};
                }
                return StatusWith<ResolvedView>(
                    {*resolvedNss, std::move(resolvedPipeline), std::move(collation.get())});
            }

            resolvedNss = &view->viewOn();
            if (!collation) {
                collation = view->defaultCollator() ? view->defaultCollator()->getSpec().toBSON()
                                                    : CollationSpec::kSimpleSpec;
            }

            // Prepend the underlying view's pipeline to the current working pipeline.
            const std::vector<BSONObj>& toPrepend = view->pipeline();
            resolvedPipeline.insert(resolvedPipeline.begin(), toPrepend.begin(), toPrepend.end());

            // If the first stage is a $collStats, then we return early with the viewOn namespace.
            if (toPrepend.size() > 0 && !toPrepend[0]["$collStats"].eoo()) {
                return StatusWith<ResolvedView>(
                    {*resolvedNss, std::move(resolvedPipeline), std::move(collation.get())});
            }
        }

        if (depth >= ViewGraph::kMaxViewDepth) {
            return {ErrorCodes::ViewDepthLimitExceeded,
                    str::stream() << "View depth too deep or view cycle detected; maximum depth is "
                                  << ViewGraph::kMaxViewDepth};
        }
    };
    MONGO_UNREACHABLE;
}
Exemplo n.º 20
0
std::shared_ptr<ViewDefinition> ViewCatalog::lookup(OperationContext* opCtx, StringData ns) {
    stdx::lock_guard<stdx::mutex> lk(_mutex);
    return _lookup(lk, opCtx, ns);
}
Exemplo n.º 21
0
// We've just seen a '<'.  Gather up stuff to closing '>' (if buffer
// ends before then, return -1).
// If it's a tag, look up the name, gather the attributes, and return
// the appropriate token.
// Else it's either just plain data or some kind of ignorable stuff:
// return Data or Comment as appropriate.
// If it's not a Comment, put it in a[*pai] and bump *pai.
static int
gettag(TokenSource* ts, int starti, Token* a, int* pai)
{
	int	rbra;
	int	ans;
	Attr*	al;
	int	nexti;
	int	c;
	int	ti;
	int	afnd;
	int	attid;
	int	quote;
	Rune*	val;
	int	nv;
	int	i;
	int	tag;
	Token*	tok;
	Rune	buf[BIGBUFSIZE];

	rbra = 0;
	nexti = ts->i;
	tok = &a[*pai];
	tok->tag = Notfound;
	tok->text = nil;
	tok->attr = nil;
	tok->starti = starti;
	c = getchar(ts);
	if(c == '/') {
		rbra = RBRA;
		c = getchar(ts);
	}
	if(c < 0)
		goto eob_done;
	if(c >= 256 || !isalpha(c)) {
		// not a tag
		if(c == '!') {
			ans = comment(ts);
			if(ans != -1)
				return ans;
			goto eob_done;
		}
		else {
			backup(ts, nexti);
			tok->tag = Data;
			tok->text = _Strdup(L"<");
			(*pai)++;
			return Data;
		}
	}
	// c starts a tagname
	buf[0] = c;
	i = 1;
	while(1) {
		c = getchar(ts);
		if(c < 0)
			goto eob_done;
		if(!ISNAMCHAR(c))
			break;
		// if name is bigger than buf it won't be found anyway...
		if(i < BIGBUFSIZE)
			buf[i++] = c;
	}
	if(_lookup(tagtable, Numtags, buf, i, &tag))
		tok->tag = tag + rbra;
	else
		tok->text = _Strndup(buf, i);	// for warning print, in build
	// attribute gathering loop
	al = nil;
	while(1) {
		// look for "ws name" or "ws name ws = ws val"  (ws=whitespace)
		// skip whitespace
attrloop_continue:
		while(c < 256 && isspace(c)) {
			c = getchar(ts);
			if(c < 0)
				goto eob_done;
		}
		if(c == '>')
			goto attrloop_done;
		if(c == '<') {
			if(warn)
				fprint(2, "warning: unclosed tag\n");
			ungetchar(ts, c);
			goto attrloop_done;
		}
		if(c >= 256 || !isalpha(c)) {
			if(warn)
				fprint(2, "warning: expected attribute name\n");
			// skipt to next attribute name
			while(1) {
				c = getchar(ts);
				if(c < 0)
					goto eob_done;
				if(c < 256 && isalpha(c))
					goto attrloop_continue;
				if(c == '<') {
					if(warn)
						fprint(2, "warning: unclosed tag\n");
					ungetchar(ts, 60);
					goto attrloop_done;
				}
				if(c == '>')
					goto attrloop_done;
			}
		}
		// gather attribute name
		buf[0] = c;
		i = 1;
		while(1) {
			c = getchar(ts);
			if(c < 0)
				goto eob_done;
			if(!ISNAMCHAR(c))
				break;
			if(i < BIGBUFSIZE-1)
				buf[i++] = c;
		}
		afnd = _lookup(attrtable, Numattrs, buf, i, &attid);
		if(warn && !afnd) {
			buf[i] = 0;
			fprint(2, "warning: unknown attribute name %S\n", buf);
		}
		// skip whitespace
		while(c < 256 && isspace(c)) {
			c = getchar(ts);
			if(c < 0)
				goto eob_done;
		}
		if(c != '=') {
			if(afnd)
				al = newattr(attid, nil, al);
			goto attrloop_continue;
		}
		//# c is '=' here;  skip whitespace
		while(1) {
			c = getchar(ts);
			if(c < 0)
				goto eob_done;
			if(c >= 256 || !isspace(c))
				break;
		}
		quote = 0;
		if(c == '\'' || c == '"') {
			quote = c;
			c = getchar(ts);
			if(c < 0)
				goto eob_done;
		}
		val = nil;
		nv = 0;
		while(1) {
valloop_continue:
			if(c < 0)
				goto eob_done;
			if(c == '>') {
				if(quote) {
					// c might be part of string (though not good style)
					// but if line ends before close quote, assume
					// there was an unmatched quote
					ti = ts->i;
					while(1) {
						c = getchar(ts);
						if(c < 0)
							goto eob_done;
						if(c == quote) {
							backup(ts, ti);
							buf[nv++] = '>';
							if(nv == BIGBUFSIZE-1) {
								val = buftostr(val, buf, nv);
								nv = 0;
							}
							c = getchar(ts);
							goto valloop_continue;
						}
						if(c == '\n') {
							if(warn)
								fprint(2, "warning: apparent unmatched quote\n");
							backup(ts, ti);
							c = '>';
							goto valloop_done;
						}
					}
				}
				else
					goto valloop_done;
			}
			if(quote) {
				if(c == quote) {
					c = getchar(ts);
					if(c < 0)
						goto eob_done;
					goto valloop_done;
				}
				if(c == '\r') {
					c = getchar(ts);
					goto valloop_continue;
				}
				if(c == '\t' || c == '\n')
					c = ' ';
			}
			else {
				if(c < 256 && isspace(c))
					goto valloop_done;
			}
			if(c == '&') {
				c = ampersand(ts);
				if(c == -1)
					goto eob_done;
			}
			buf[nv++] = c;
			if(nv == BIGBUFSIZE-1) {
				val = buftostr(val, buf, nv);
				nv = 0;
			}
			c = getchar(ts);
		}
valloop_done:
		if(afnd) {
			val = buftostr(val, buf, nv);
			al = newattr(attid, val, al);
		}
	}

attrloop_done:
	tok->attr = al;
	(*pai)++;
	return tok->tag;

eob_done:
	if(warn)
		fprint(2, "warning: incomplete tag at end of page\n");
	backup(ts, nexti);
	tok->tag = Data;
	tok->text = _Strdup(L"<");
	return Data;
}
const SkMemberInfo* SkMemberInfo::Find(SkDisplayTypes type, const char** matchPtr) {
    int lookup = _searchByType(type);
    SkASSERT(lookup >= 0);
    return _lookup(lookup, matchPtr);
}
Exemplo n.º 23
0
static int
parse_form(char **fmtp, format_data_t *form)
{
	char *formname, *p;
	format_key_t *key_head, *key_tail;
	
	++*fmtp;

	formname = get_token(fmtp);
	if (strcmp(formname, "newline") == 0) {
		form->type = FDATA_NEWLINE;
		p = get_token(fmtp);
		if (p[0] != ')') {
			form->v.nl = strtol(p, NULL, 0);
			p = get_token(fmtp);
		} else
			form->v.nl = 1;
	} else if (strcmp(formname, "tab") == 0) {
		form->type = FDATA_TAB;
		p = get_token(fmtp);
		if (p[0] != ')') {
			form->v.tabstop = strtol(p, NULL, 0);
			p = get_token(fmtp);
		} else
			form->v.tabstop = 1;
	} else {
		radutent_fh_t fh;
		int arg;
		
		fh = _lookup(formname);
		if (!fh) {
			grad_log(GRAD_LOG_ERR,
			         _("error in format spec: unknown format %s"),
			         formname);
			return 1;
		}
		
		form->type = FDATA_FH;
		form->v.fh.fun = fh;

		/* Collect optional arguments */
		arg = 0;
		while ((p = get_token(fmtp)) != NULL &&
		       !(p[0] == ':' || p[0] == ')')) {
			arg++;
			switch (arg) {
			case 1: /* width */
				form->v.fh.width = strtol(p, NULL, 0);
				break;
			case 2: /* header */
				form->v.fh.header = grad_estrdup(p);
				break;
			default:
				grad_log(GRAD_LOG_ERR,
				     _("wrong number of arguments to form %s"),
				         formname);
				return 1;
			}
		}
		
		/* Collect keyword arguments */
		key_head = NULL;
		while (p && p[0] == ':') {
			format_key_t *key = grad_emalloc(sizeof(*key));
			if (!key_head)
				key_head = key;
			else
				key_tail->next = key;
			key_tail = key;
			key->name = grad_estrdup(p+1);
			p = get_token(fmtp);
			if (p[0] == ')' || p[0] == ':')
				key->value = grad_estrdup("t");
			else {
				key->value = grad_estrdup(p);
				p = get_token(fmtp);
			}
		}
		form->key = key_head;
	}
	
	if (p[0] != ')') {
		grad_log(GRAD_LOG_ERR, _("form `%s' not closed"), formname);
		return 1;
	}
	return 0;
}