+static XBT_INLINE void diff_push(xbt_dynar_t dyn, char prefix, const char *s)
+{
+ char *topush = bprintf("%c %s", prefix, s);
+ xbt_dynar_push(dyn, &topush);
+}
+
+static int diff_member(const char *s, xbt_dynar_t d, unsigned from, unsigned to)
+{
+ unsigned i;
+ for (i = from; i < to; i++)
+ if (!strcmp(s, xbt_dynar_get_as(d, i, char *)))
+ return 1;
+ return 0;
+}
+
+static void diff_easy_prefix(xbt_dynar_t res, xbt_dynar_t da, xbt_dynar_t db)
+{
+ while (xbt_dynar_length(da) > 0 && xbt_dynar_length(db) > 0) {
+ char *sa = xbt_dynar_getfirst_as(da, char *);
+ char *sb = xbt_dynar_getfirst_as(db, char *);
+
+ if (!strcmp(sa, sb)) {
+ /* sa == sb */
+ diff_push(res, ' ', sa);
+ xbt_dynar_shift(da, NULL);
+ xbt_dynar_shift(db, NULL);
+ } else if (!diff_member(sa, db, 1, xbt_dynar_length(db))) {
+ /* sa not in db */
+ diff_push(res, '-', sa);
+ xbt_dynar_shift(da, NULL);
+ } else if (!diff_member(sb, da, 1, xbt_dynar_length(da))) {
+ /* sb not in da */
+ diff_push(res, '+', sb);
+ xbt_dynar_shift(db, NULL);
+ } else {
+ /* sa in db, and sb in da: cannot go further */
+ return;
+ }
+ }
+}
+
+static void diff_easy_suffix(xbt_dynar_t res, xbt_dynar_t da, xbt_dynar_t db)
+{
+ while (xbt_dynar_length(da) > 0 && xbt_dynar_length(db) > 0) {
+ char *sa = xbt_dynar_getlast_as(da, char *);
+ char *sb = xbt_dynar_getlast_as(db, char *);
+
+ if (!strcmp(sa, sb)) {
+ /* sa == sb */
+ diff_push(res, ' ', sa);
+ xbt_dynar_pop(da, NULL);
+ xbt_dynar_pop(db, NULL);
+ } else if (!diff_member(sb, da, 0, xbt_dynar_length(da) - 1)) {
+ /* sb not in da */
+ diff_push(res, '+', sb);
+ xbt_dynar_pop(db, NULL);
+ } else if (!diff_member(sa, db, 0, xbt_dynar_length(db) - 1)) {
+ /* sa not in db */
+ diff_push(res, '-', sa);
+ xbt_dynar_pop(da, NULL);
+ } else {
+ /* sa in db, and sb in da: cannot go further */
+ return;
+ }
+ }
+}
+