/* tsort.c - topological sort dependency resolver * * Copyright 2023 Rob Landley * * See http://opengroup.org/onlinepubs/9699919799/utilities/tsort.html USE_TSORT(NEWTOY(tsort, ">1", TOYFLAG_USR|TOYFLAG_BIN)) config TSORT bool "tsort" default y help usage: tsort [FILE] Topological sort dependency resolver. Read pairs of input strings indicating before/after dependency relationships and find an ordering that respects all dependencies. On success output each string once to stdout, on failure print error and output cycle pairs. */ #include "toys.h" // Comparison callback for qsort and bsearch: sort by second element static int sbse(char **a, char **b) { return strcmp(a[1], b[1]); } // Read pairs of "A must go before B" input strings into pair list. Sort pair // list by second element. Loop over list to find pairs where the first string // is not any pair's second string (I.E. nothing depends on this) and remove // each pair from list. For each removed pair, add first string to output // list, and also add second string to output if after removing it no other // pair has it as the second string. Suppress duplicates by checking each // string added to output against the strings added in the last 2 passes // through the pair list. (Because "a b c a" removes "c a" pair after checking // "a b" pair, so removing "a b" next pass would try to output "a" again.) // If a pass through the pair list finds no pairs to remove, what's left is // all circular dependencies. // TODO: this treats NUL in input as EOF static void do_tsort(int fd, char *name) { off_t plen = 0; char *ss, **pair, *keep[2]; long count, // remaining unprocessed pairs len, // total strings in pair list out, // most recently added output (counts down from len) otop, // out at start of this loop over pair[] otop2, // out at start of previous loop over pair[] ii, jj, kk; unsigned long sigh; // bsearch()'s first argument is the element to search for, // and sbse() compares the second element of each pair, so to find // which FIRST element matches a second element, we need to feed bsearch // keep-1 but the compiler clutches its pearls about this even when // typecast to (void *), so do the usual LP64 trick to MAKE IT SHUT UP. // (The search function adds 1 to each argument so we never access // memory outside the pair.) sigh = ((unsigned long)keep)-sizeof(*keep); // Count input entries in data block read from fd if (!(ss = readfd(fd, 0, &plen))) return; for (ii = len = 0; ii=plen) break; pair[len] = ss+ii; while (iiout) xprintf("%s\n", pair[--len]); } void tsort_main(void) { loopfiles(toys.optargs, do_tsort); }