]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
this has been unused for a long time
authorAlan T. DeKok <aland@freeradius.org>
Fri, 10 Dec 2021 19:43:44 +0000 (14:43 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 10 Dec 2021 19:43:44 +0000 (14:43 -0500)
src/lib/util/dpair_legacy.c [deleted file]

diff --git a/src/lib/util/dpair_legacy.c b/src/lib/util/dpair_legacy.c
deleted file mode 100644 (file)
index 97066d3..0000000
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
- *   This library is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU Lesser General Public
- *   License as published by the Free Software Foundation; either
- *   version 2.1 of the License, or (at your option) any later version.
- *
- *   This library 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
- *   Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public
- *   License along with this library; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/** AVP manipulation and search API
- *
- * @file src/lib/util/pair.c
- *
- * @copyright 2000,2006,2015 The FreeRADIUS server project
- */
-RCSID("$Id$")
-
-#include <freeradius-devel/util/misc.h>
-#include <freeradius-devel/util/pair.h>
-#include <freeradius-devel/util/pair_legacy.h>
-#include <freeradius-devel/util/proto.h>
-#include <freeradius-devel/util/regex.h>
-
-#include <freeradius-devel/protocol/radius/rfc2865.h>
-#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
-
-
-fr_sbuff_term_t const          bareword_terminals =
-                               FR_SBUFF_TERMS(
-                                       L("\t"),
-                                       L("\n"),
-                                       L(" "),
-                                       L("!*"),
-                                       L("!="),
-                                       L("!~"),
-                                       L("&&"),                /* Logical operator */
-                                       L(")"),                 /* Close condition/sub-condition */
-                                       L("+="),
-                                       L("-="),
-                                       L(":="),
-                                       L("<"),
-                                       L("<="),
-                                       L("=*"),
-                                       L("=="),
-                                       L("=~"),
-                                       L(">"),
-                                       L(">="),
-                                       L("||"),                /* Logical operator */
-                               );
-
-/** Mark a valuepair for xlat expansion
- *
- * Copies xlat source (unprocessed) string to valuepair value, and sets value type.
- *
- * @param vp to mark for expansion.
- * @param value to expand.
- * @return
- *     - 0 if marking succeeded.
- *     - -1 if #fr_pair_t already had a value, or OOM.
- */
-int fr_pair_mark_xlat(fr_pair_t *vp, char const *value)
-{
-       char *raw;
-
-       /*
-        *      valuepair should not already have a value.
-        */
-       if (vp->type != VT_NONE) {
-               fr_strerror_const("Pair already has a value");
-               return -1;
-       }
-
-       raw = talloc_typed_strdup(vp, value);
-       if (!raw) {
-               fr_strerror_const("Out of memory");
-               return -1;
-       }
-
-       vp->type = VT_XLAT;
-       vp->xlat = raw;
-       vp->vp_length = 0;
-
-       return 0;
-}
-
-/** Create a valuepair from an ASCII attribute and value
- *
- * Where the attribute name is in the form:
- *  - Attr-%d
- *  - Attr-%d.%d.%d...
- *
- * @param ctx for talloc
- * @param dict to user for partial resolution.
- * @param attribute name to parse.
- * @param value to parse (must be a hex string).
- * @param op to assign to new valuepair.
- * @return new #fr_pair_t or NULL on error.
- */
-static fr_pair_t *fr_pair_make_unknown(TALLOC_CTX *ctx, fr_dict_t const *dict,
-                                       char const *attribute, char const *value,
-                                       fr_token_t op)
-{
-       fr_pair_t               *vp;
-       fr_dict_attr_t          *n;
-       fr_sbuff_t              sbuff = FR_SBUFF_IN(attribute, strlen(attribute));
-
-       vp = fr_pair_alloc_null(ctx);
-       if (!vp) return NULL;
-
-       if ((fr_dict_unknown_afrom_oid_substr(vp, NULL, &n, fr_dict_root(dict), &sbuff, NULL) <= 0) ||
-                                             fr_sbuff_remaining(&sbuff)) {
-               talloc_free(vp);
-               return NULL;
-       }
-       vp->da = n;
-
-       /*
-        *      No value, but ensure that we still set up vp->data properly.
-        */
-       if (!value) {
-               value = "";
-
-       } else if (strncasecmp(value, "0x", 2) != 0) {
-               /*
-                *      Unknown attributes MUST be of type 'octets'
-                */
-               fr_strerror_printf("Unknown attribute \"%s\" requires a hex "
-                                  "string, not \"%s\"", attribute, value);
-               talloc_free(vp);
-               return NULL;
-       }
-
-       if (fr_pair_value_from_str(vp, value, strlen(value), &fr_value_unescape_double, false) < 0) {
-               talloc_free(vp);
-               return NULL;
-       }
-
-       vp->op = (op == 0) ? T_OP_EQ : op;
-       return vp;
-}
-
-/** Create a #fr_pair_t from ASCII strings
- *
- * Converts an attribute string identifier (with an optional tag qualifier)
- * and value string into a #fr_pair_t.
- *
- * The string value is parsed according to the type of #fr_pair_t being created.
- *
- * @param[in] ctx      for talloc.
- * @param[in] dict     to look attributes up in.
- * @param[in] vps      list where the attribute will be added (optional)
- * @param[in] attribute        name.
- * @param[in] value    attribute value (may be NULL if value will be set later).
- * @param[in] op       to assign to new #fr_pair_t.
- * @return a new #fr_pair_t.
- */
-fr_pair_t *fr_pair_make(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *vps,
-                       char const *attribute, char const *value, fr_token_t op)
-{
-       fr_dict_attr_t const    *da;
-       fr_pair_t               *vp;
-       char const              *attrname = attribute;
-
-       /*
-        *      It's not found in the dictionary, so we use
-        *      another method to create the attribute.
-        */
-       da = fr_dict_attr_search_by_qualified_oid(NULL, dict, attrname, true);
-       if (!da) {
-               vp = fr_pair_make_unknown(ctx, dict, attrname, value, op);
-               if (!vp) return NULL;
-
-               if (vps) fr_pair_add(vps, vp);
-               return vp;
-       }
-
-       if (da->type == FR_TYPE_GROUP) {
-               fr_strerror_const("Attributes of type 'group' are not supported");
-               return NULL;
-       }
-
-       vp = fr_pair_afrom_da(ctx, da);
-       if (!vp) return NULL;
-       vp->op = (op == 0) ? T_OP_EQ : op;
-
-       switch (vp->op) {
-       case T_OP_CMP_TRUE:
-       case T_OP_CMP_FALSE:
-               fr_pair_value_clear(vp);
-               value = NULL;   /* ignore it! */
-               break;
-
-               /*
-                *      Regular expression comparison of integer attributes
-                *      does a STRING comparison of the names of their
-                *      integer attributes.
-                */
-       case T_OP_REG_EQ:       /* =~ */
-       case T_OP_REG_NE:       /* !~ */
-       {
-#ifndef HAVE_REGEX
-               fr_strerror_const("Regular expressions are not supported");
-               return NULL;
-#else
-               ssize_t slen;
-               regex_t *preg;
-
-               /*
-                *      Someone else will fill in the value.
-                */
-               if (!value) break;
-
-               talloc_free(vp);
-
-               slen = regex_compile(ctx, &preg, value, strlen(value), NULL, false, true);
-               if (slen <= 0) {
-                       fr_strerror_printf_push("Error at offset %zu compiling regex for %s", -slen, attribute);
-                       return NULL;
-               }
-               talloc_free(preg);
-
-               vp = fr_pair_afrom_da(ctx, da);
-               if (!vp) return NULL;
-               vp->op = op;
-
-               if (fr_pair_mark_xlat(vp, value) < 0) {
-                       talloc_free(vp);
-                       return NULL;
-               }
-
-               value = NULL;   /* ignore it */
-               break;
-#endif
-       }
-       default:
-               break;
-       }
-
-       /*
-        *      We probably want to fix fr_pair_value_from_str to accept
-        *      octets as values for any attribute.
-        */
-       if (value && (fr_pair_value_from_str(vp, value, strlen(value), &fr_value_unescape_double, true) < 0)) {
-               talloc_free(vp);
-               return NULL;
-       }
-
-       if (vps) fr_pair_add(vps, vp);
-       return vp;
-}
-
-/** Read one line of attribute/value pairs into a list.
- *
- * The line may specify multiple attributes separated by commas.
- *
- * @note If the function returns #T_INVALID, an error has occurred and
- * @note the valuepair list should probably be freed.
- *
- * @param[in] ctx      for talloc
- * @param[in] parent   parent to start referencing from
- * @param[in] buffer   to read valuepairs from.
- * @param[in] list     where the parsed fr_pair_ts will be appended.
- * @param[in,out] token        The last token we parsed
- * @param[in] depth    the nesting depth for FR_TYPE_GROUP
- * @return
- *     - <= 0 on failure.
- *     - The number of bytes of name consumed on success.
- */
-static ssize_t fr_pair_list_afrom_substr(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, char const *buffer,
-                                        fr_pair_list_t *list, fr_token_t *token, int depth)
-{
-       fr_pair_list_t  tmp_list;
-       fr_pair_t       *vp;
-       char const      *p, *next;
-       fr_token_t      last_token = T_INVALID;
-       fr_pair_t_RAW   raw;
-       fr_dict_attr_t  const *internal = fr_dict_root(fr_dict_internal());
-
-       if (internal == parent) internal = NULL;
-
-       /*
-        *      We allow an empty line.
-        */
-       if (buffer[0] == 0) {
-               *token = T_EOL;
-               return 0;
-       }
-
-       fr_pair_list_init(&tmp_list);
-
-       p = buffer;
-       while (true) {
-               ssize_t slen;
-               fr_dict_attr_t const *da;
-               fr_dict_attr_t *da_unknown = NULL;
-               fr_skip_whitespace(p);
-
-               /*
-                *      Stop at the end of the input, returning
-                *      whatever token was last read.
-                */
-               if (!*p) break;
-
-               if (*p == '#') {
-                       last_token = T_EOL;
-                       break;
-               }
-
-               /*
-                *      Hacky hack...
-                */
-               if (strncmp(p, "raw.", 4) == 0) goto do_unknown;
-
-               /*
-                *      Parse the name.
-                */
-               slen = fr_dict_attr_by_oid_substr(NULL, &da, parent,
-                                                 &FR_SBUFF_IN(p, strlen(p)), &bareword_terminals);
-               if ((slen <= 0) && internal) {
-                       slen = fr_dict_attr_by_oid_substr(NULL, &da, internal,
-                                                         &FR_SBUFF_IN(p, strlen(p)), &bareword_terminals);
-               }
-               if (slen <= 0) {
-               do_unknown:
-                       slen = fr_dict_unknown_afrom_oid_substr(ctx, NULL, &da_unknown, parent,
-                                                               &FR_SBUFF_IN(p, strlen(p)), &bareword_terminals);
-                       if (slen <= 0) {
-                               p += -slen;
-
-                       error:
-                               fr_pair_list_free(&tmp_list);
-                               *token = T_INVALID;
-                               return -(p - buffer);
-                       }
-
-                       da = da_unknown;
-               }
-
-               next = p + slen;
-
-               if ((size_t) (next - p) >= sizeof(raw.l_opand)) {
-                       fr_dict_unknown_free(&da);
-                       fr_strerror_const("Attribute name too long");
-                       goto error;
-               }
-
-               memcpy(raw.l_opand, p, next - p);
-               raw.l_opand[next - p] = '\0';
-               raw.r_opand[0] = '\0';
-
-               p = next;
-               fr_skip_whitespace(p);
-
-               /*
-                *      There must be an operator here.
-                */
-               raw.op = gettoken(&p, raw.r_opand, sizeof(raw.r_opand), false);
-               if ((raw.op  < T_EQSTART) || (raw.op  > T_EQEND)) {
-                       fr_dict_unknown_free(&da);
-                       fr_strerror_const("Expecting operator");
-                       goto error;
-               }
-
-               fr_skip_whitespace(p);
-
-               /*
-                *      Allow grouping attributes.
-                */
-               if ((da->type == FR_TYPE_GROUP) || (da->type == FR_TYPE_TLV) || (da->type == FR_TYPE_STRUCT)) {
-                       if (*p != '{') {
-                               fr_strerror_printf("Group list for %s MUST start with '{'", da->name);
-                               goto error;
-                       }
-                       p++;
-
-                       vp = fr_pair_afrom_da(ctx, da);
-                       if (!vp) goto error;
-
-                       /*
-                        *      Find the new root attribute to start encoding from.
-                        */
-                       parent = fr_dict_attr_ref(da);
-                       if (!parent) parent = da;
-
-                       slen = fr_pair_list_afrom_substr(vp, parent, p, &vp->vp_group, &last_token, depth + 1);
-                       if (slen <= 0) {
-                               talloc_free(vp);
-                               goto error;
-                       }
-
-                       if (last_token != T_RCBRACE) {
-                       failed_group:
-                               fr_strerror_const("Failed to end group list with '}'");
-                               talloc_free(vp);
-                               goto error;
-                       }
-
-                       p += slen;
-                       fr_skip_whitespace(p);
-                       if (*p != '}') goto failed_group;
-                       p++;
-
-               } else {
-                       fr_token_t quote;
-                       char const *q;
-
-                       /*
-                        *      Get the RHS thing.
-                        */
-                       quote = gettoken(&p, raw.r_opand, sizeof(raw.r_opand), false);
-                       if (quote == T_EOL) {
-                               fr_strerror_const("Failed to get value");
-                               goto error;
-                       }
-
-                       switch (quote) {
-                               /*
-                                *      Perhaps do xlat's
-                                */
-                       case T_DOUBLE_QUOTED_STRING:
-                               /*
-                                *      Only report as double quoted if it contained valid
-                                *      a valid xlat expansion.
-                                */
-                               q = strchr(raw.r_opand, '%');
-                               if (q && (q[1] == '{')) {
-                                       raw.quote = quote;
-                               } else {
-                                       raw.quote = T_SINGLE_QUOTED_STRING;
-                               }
-                               break;
-
-                       case T_SINGLE_QUOTED_STRING:
-                       case T_BACK_QUOTED_STRING:
-                       case T_BARE_WORD:
-                               raw.quote = quote;
-                               break;
-
-                       default:
-                               fr_strerror_printf("Failed to find expected value on right hand side in %s", da->name);
-                               goto error;
-                       }
-
-                       fr_skip_whitespace(p);
-
-                       /*
-                        *      Regular expressions get sanity checked by pair_make().
-                        *
-                        *      @todo - note that they will also be escaped,
-                        *      so we may need to fix that later.
-                        */
-                       if ((raw.op == T_OP_REG_EQ) || (raw.op == T_OP_REG_NE)) {
-                               vp = fr_pair_afrom_da(ctx, da);
-                               if (!vp) goto error;
-                               vp->op = raw.op;
-
-                               fr_pair_value_bstrndup(vp, raw.r_opand, strlen(raw.r_opand), false);
-                       } else {
-                               /*
-                                *      All other attributes get the name
-                                *      parsed.
-                                */
-                               vp = fr_pair_afrom_da(ctx, da);
-                               if (!vp) goto error;
-                               vp->op = raw.op;
-
-                               /*
-                                *      We don't care what the value is, so
-                                *      ignore it.
-                                */
-                               if ((raw.op == T_OP_CMP_TRUE) || (raw.op == T_OP_CMP_FALSE)) goto next;
-
-                               /*
-                                *      fr_pair_raw_from_str() only returns this when
-                                *      the input looks like it needs to be xlat'd.
-                                */
-                               if (raw.quote == T_DOUBLE_QUOTED_STRING) {
-                                       if (fr_pair_mark_xlat(vp, raw.r_opand) < 0) {
-                                               talloc_free(vp);
-                                               goto error;
-                                       }
-
-                                       /*
-                                        *      Parse it ourselves.  The RHS
-                                        *      might NOT be tainted, but we
-                                        *      don't know.  So just mark it
-                                        *      as such to be safe.
-                                        */
-                               } else if (fr_pair_value_from_str(vp, raw.r_opand, strlen(raw.r_opand),
-                                          fr_value_unescape_by_quote[raw.quote], true) < 0) {
-                                       talloc_free(vp);
-                                       goto error;
-                               }
-                       }
-               }
-
-       next:
-               /*
-                *      Free the unknown attribute, we don't need it any more.
-                */
-               fr_dict_unknown_free(&da);
-
-               fr_pair_add(&tmp_list, vp);
-
-               /*
-                *      Now look for EOL, hash, etc.
-                */
-               if (!*p || (*p == '#') || (*p == '\n')) {
-                       last_token = T_EOL;
-                       break;
-               }
-
-               /*
-                *      Check for nested groups.
-                */
-               if ((depth > 0) && (p[0] == ' ') && (p[1] == '}')) p++;
-
-               /*
-                *      Stop at '}', too, if we're inside of a group.
-                */
-               if ((depth > 0) && (*p == '}')) {
-                       last_token = T_RCBRACE;
-                       break;
-               }
-
-               if (*p != ',') {
-                       fr_strerror_printf("Expected ',', got '%c' at offset %zu", *p, p - buffer);
-                       goto error;
-               }
-               p++;
-               last_token = T_COMMA;
-       }
-
-       if (!fr_pair_list_empty(&tmp_list)) fr_tmp_pair_list_move(list, &tmp_list);
-
-       /*
-        *      And return the last token which we read.
-        */
-       *token = last_token;
-       return p - buffer;
-}
-
-/** Read one line of attribute/value pairs into a list.
- *
- * The line may specify multiple attributes separated by commas.
- *
- * @note If the function returns #T_INVALID, an error has occurred and
- * @note the valuepair list should probably be freed.
- *
- * @param[in] ctx      for talloc
- * @param[in] dict     to resolve attributes in.
- * @param[in] buffer   to read valuepairs from.
- * @param[in] list     where the parsed fr_pair_ts will be appended.
- * @return the last token parsed, or #T_INVALID
- */
-fr_token_t fr_pair_list_afrom_str(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *buffer, fr_pair_list_t *list)
-{
-       fr_token_t token;
-
-       (void) fr_pair_list_afrom_substr(ctx, fr_dict_root(dict), buffer, list, &token, 0);
-       return token;
-}
-
-/** Read valuepairs from the fp up to End-Of-File.
- *
- * @param[in] ctx              for talloc
- * @param[in] dict             to resolve attributes in.
- * @param[in,out] out          where the parsed fr_pair_ts will be appended.
- * @param[in] fp               to read valuepairs from.
- * @param[out] pfiledone       true if file parsing complete;
- * @return
- *     - 0 on success
- *     - -1 on error
- */
-int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone)
-{
-       fr_token_t      last_token = T_EOL;
-       bool            found = false;
-       char            buf[8192];
-
-       while (fgets(buf, sizeof(buf), fp) != NULL) {
-               fr_pair_list_t tmp_list;
-
-               /*
-                *      If we get a '\n' by itself, we assume that's
-                *      the end of that VP list.
-                */
-               if (buf[0] == '\n') {
-                       if (found) {
-                               *pfiledone = false;
-                               return 0;
-                       }
-                       continue;
-               }
-
-               /*
-                *      Comments get ignored
-                */
-               if (buf[0] == '#') continue;
-
-               /*
-                *      Read all of the attributes on the current line.
-                *
-                *      If we get nothing but an EOL, it's likely OK.
-                */
-               fr_pair_list_init(&tmp_list);
-               last_token = fr_pair_list_afrom_str(ctx, dict, buf, &tmp_list);
-               if (fr_dlist_empty(&tmp_list.head)) {
-                       if (last_token == T_EOL) break;
-
-                       /*
-                        *      Didn't read anything, but the previous
-                        *      line wasn't EOL.  The input file has a
-                        *      format error.
-                        */
-                       *pfiledone = false;
-                       fr_pair_list_free(out);
-                       return -1;
-               }
-
-               found = true;
-               fr_tmp_pair_list_move(out, &tmp_list);
-       }
-
-       *pfiledone = true;
-       return 0;
-}
-
-
-/** Move pairs from source list to destination list respecting operator
- *
- * @note This function does some additional magic that's probably not needed
- *      in most places. Consider using radius_pairmove in server code.
- *
- * @note fr_pair_list_free should be called on the head of the source list to free
- *      unmoved attributes (if they're no longer needed).
- *
- * @param[in,out] to destination list.
- * @param[in,out] from source list.
- *
- * @see radius_pairmove
- */
-void fr_pair_list_move_op(fr_pair_list_t *to, fr_pair_list_t *from, fr_token_t op)
-{
-       fr_pair_t *i, *found;
-       fr_pair_list_t head_new, head_prepend;
-
-       if (!to || fr_pair_list_empty(from)) return;
-
-       /*
-        *      We're editing the "to" list while we're adding new
-        *      attributes to it.  We don't want the new attributes to
-        *      be edited, so we create an intermediate list to hold
-        *      them during the editing process.
-        */
-       fr_pair_list_init(&head_new);
-       fr_pair_list_init(&head_prepend);
-
-       /*
-        *      We're looping over the "from" list, moving some
-        *      attributes out, but leaving others in place.
-        */
-       for (i = fr_pair_list_head(from); i; ) {
-               fr_pair_t *j;
-
-               PAIR_VERIFY(i);
-
-               /*
-                *      We never move Fall-Through.
-                */
-               if (fr_dict_attr_is_top_level(i->da) && (i->da->attr == FR_FALL_THROUGH)) {
-                       i = fr_pair_list_next(from, i);
-                       continue;
-               }
-
-               /*
-                *      Unlike previous versions, we treat all other
-                *      attributes as normal.  i.e. there's no special
-                *      treatment for passwords or Hint.
-                */
-
-               switch (i->op) {
-               /*
-                *      Anything else are operators which
-                *      shouldn't occur.  We ignore them, and
-                *      leave them in place.
-                */
-               default:
-                       i = fr_pair_list_next(from, i);
-                       continue;
-
-               /*
-                *      Add it to the "to" list, but only if
-                *      it doesn't already exist.
-                */
-               case T_OP_EQ:
-                       found = fr_pair_find_by_da_idx(to, i->da);
-                       if (!found) goto do_add;
-
-                       i = fr_pair_list_next(from, i);
-                       continue;
-
-               /*
-                *      Add it to the "to" list, and delete any attribute
-                *      of the same vendor/attr which already exists.
-                */
-               case T_OP_SET:
-                       found = fr_pair_find_by_da_idx(to, i->da);
-                       if (!found) goto do_add;
-
-                       /*
-                        *      Delete *all* of the attributes
-                        *      of the same number.
-                        */
-                       fr_pair_delete_by_da(to, found->da);
-                       goto do_add;
-
-               /*
-                *      Move it from the old list and add it
-                *      to the new list.
-                */
-               case T_OP_ADD_EQ:
-       do_add:
-                       j = fr_pair_list_next(from, i);
-                       fr_pair_remove(from, i);
-                       fr_pair_add(&head_new, i);
-                       i = j;
-                       continue;
-               case T_OP_PREPEND:
-                       j = fr_pair_list_next(from, i);
-                       fr_pair_remove(from, i);
-                       fr_pair_prepend(&head_prepend, i);
-                       i = j;
-                       continue;
-               }
-       } /* loop over the "from" list. */
-
-       /*
-        *      If the op parameter was prepend add the "new" list
-        *      attributes first as those whose individual operator
-        *      is prepend should be prepended to the resulting list
-        */
-       if (op == T_OP_PREPEND) fr_tmp_pair_list_move_head(to, &head_new);
-
-       /*
-        *      If there are any items in the prepend list prepend
-        *      it to the "to" list
-        */
-       fr_tmp_pair_list_move_head(to, &head_prepend);
-
-       /*
-        *      If the op parameter was not prepend, take the "new"
-        *      list and append it to the "to" list
-        */
-       if (op != T_OP_PREPEND) fr_tmp_pair_list_move(to, &head_new);
-}