@@ -318,6 +318,67 @@ lyd_diff_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, struct
318318 lyd_insert_node (NULL , first_sibling , node , LYD_INSERT_NODE_LAST_BY_SCHEMA );
319319}
320320
321+ /**
322+ * @brief Duplicate a node with any parents and connect it to the parent, if any.
323+ *
324+ * @param[in] node Node to duplicate.
325+ * @param[in] op Diff operation.
326+ * @param[in] parent Parent to connect to, if any.
327+ * @param[in,out] first First top-level node.
328+ * @param[out] dup Duplicated @p node.
329+ * @return LY_ERR value.
330+ */
331+ static LY_ERR
332+ lyd_diff_dup (const struct lyd_node * node , enum lyd_diff_op op , struct lyd_node * parent , struct lyd_node * * first ,
333+ struct lyd_node * * dup )
334+ {
335+ struct lyd_node * dup_parent , * d ;
336+ const struct lyd_node * node_parent ;
337+ const struct lysc_node * sparent ;
338+ uint32_t diff_opts ;
339+
340+ diff_opts = LYD_DUP_NO_META | LYD_DUP_WITH_FLAGS ;
341+ if (lysc_is_userordered (node -> schema )) {
342+ diff_opts |= LYD_DUP_NO_LYDS ;
343+ }
344+ if ((op != LYD_DIFF_OP_REPLACE ) || !lysc_is_userordered (node -> schema ) || (node -> schema -> flags & LYS_CONFIG_R )) {
345+ /* move applies only to the user-ordered list, no descendants */
346+ diff_opts |= LYD_DUP_RECURSIVE ;
347+ }
348+
349+ /* duplicate the node */
350+ LY_CHECK_RET (lyd_dup_single (node , NULL , diff_opts , dup ));
351+
352+ dup_parent = * dup ;
353+ node_parent = node ;
354+ sparent = parent ? parent -> schema : NULL ;
355+ while (lysc_data_parent (dup_parent -> schema ) &&
356+ !lyd_compare_schema_equal (lysc_data_parent (dup_parent -> schema ), sparent )) {
357+ node_parent = node_parent -> parent ;
358+
359+ /* duplicate the next parent */
360+ LY_CHECK_RET (lyd_dup_single (node_parent , NULL , LYD_DUP_NO_META | LYD_DUP_WITH_FLAGS , & d ));
361+
362+ /* connect the existing dup tree into the parent */
363+ lyd_insert_node (d , NULL , dup_parent , LYD_INSERT_NODE_DEFAULT );
364+ dup_parent = d ;
365+ }
366+
367+ /* connect to the parent/data tree */
368+ if (parent ) {
369+ lyd_insert_node (parent , NULL , dup_parent , LYD_INSERT_NODE_DEFAULT );
370+ } else {
371+ lyd_diff_insert_sibling (* first , dup_parent , first );
372+ }
373+
374+ /* add parent operation, if any */
375+ if (dup_parent != * dup ) {
376+ LY_CHECK_RET (lyd_new_meta (NULL , dup_parent , NULL , "yang:operation" , "none" , LYD_NEW_VAL_STORE_ONLY , NULL ));
377+ }
378+
379+ return LY_SUCCESS ;
380+ }
381+
321382LY_ERR
322383lyd_diff_add (const struct lyd_node * node , enum lyd_diff_op op , const char * orig_default , const char * orig_value ,
323384 const char * key , const char * value , const char * position , const char * orig_key , const char * orig_position ,
@@ -327,7 +388,6 @@ lyd_diff_add(const struct lyd_node *node, enum lyd_diff_op op, const char *orig_
327388 const struct lyd_node * parent = NULL ;
328389 enum lyd_diff_op cur_op ;
329390 struct lyd_meta * meta ;
330- uint32_t diff_opts ;
331391 ly_bool found ;
332392
333393 assert (diff );
@@ -406,47 +466,8 @@ lyd_diff_add(const struct lyd_node *node, enum lyd_diff_op op, const char *orig_
406466
407467 dup = diff_parent ;
408468 } else {
409- diff_opts = LYD_DUP_NO_META | LYD_DUP_WITH_PARENTS | LYD_DUP_WITH_FLAGS ;
410- if (lysc_is_userordered (node -> schema )) {
411- diff_opts |= LYD_DUP_NO_LYDS ;
412- }
413- if ((op != LYD_DIFF_OP_REPLACE ) || !lysc_is_userordered (node -> schema ) || (node -> schema -> flags & LYS_CONFIG_R )) {
414- /* move applies only to the user-ordered list, no descendants */
415- diff_opts |= LYD_DUP_RECURSIVE ;
416- }
417-
418469 /* duplicate the subtree (and connect to the diff if possible) */
419- if (diff_parent && (LYD_CTX (diff_parent ) != LYD_CTX (node ))) {
420- LY_CHECK_RET (lyd_dup_single_to_ctx (node , LYD_CTX (diff_parent ), diff_parent , diff_opts , & dup ));
421- } else {
422- LY_CHECK_RET (lyd_dup_single (node , diff_parent , diff_opts , & dup ));
423- }
424-
425- /* find the first duplicated parent */
426- if (!diff_parent ) {
427- diff_parent = dup -> parent ;
428- while (diff_parent && diff_parent -> parent ) {
429- diff_parent = diff_parent -> parent ;
430- }
431- } else {
432- diff_parent = dup ;
433- while (diff_parent -> parent && (diff_parent -> parent -> schema == parent -> schema )) {
434- diff_parent = diff_parent -> parent ;
435- }
436- }
437-
438- /* no parent existed, must be manually connected */
439- if (!diff_parent ) {
440- /* there actually was no parent to duplicate */
441- lyd_diff_insert_sibling (* diff , dup , diff );
442- } else if (!diff_parent -> parent ) {
443- lyd_diff_insert_sibling (* diff , diff_parent , diff );
444- }
445-
446- /* add parent operation, if any */
447- if (diff_parent && (diff_parent != dup )) {
448- LY_CHECK_RET (lyd_new_meta (NULL , diff_parent , NULL , "yang:operation" , "none" , LYD_NEW_VAL_STORE_ONLY , NULL ));
449- }
470+ LY_CHECK_RET (lyd_diff_dup (node , op , diff_parent , diff , & dup ));
450471 }
451472
452473 /* add subtree operation if needed */
0 commit comments