+ again:
+ Score_element *sc = unsmob_element (src);
+ if (sc)
+ {
+ if (gh_number_p (criterion))
+ {
+ Item * i = dynamic_cast<Item*> (sc);
+ Direction d = to_dir (criterion);
+ if (i && i->break_status_dir () != d)
+ {
+ Item *br = i->find_prebroken_piece (d);
+ return (br) ? br->self_scm () : SCM_UNDEFINED;
+ }
+ }
+ else
+ {
+ Line_of_score * line
+ = dynamic_cast<Line_of_score*> (unsmob_element (criterion));
+ if (sc->line_l () != line)
+ {
+ sc = sc->find_broken_piece (line);
+
+ }
+
+ /* now: !sc || (sc && sc->line_l () == line) */
+ if (!sc)
+ return SCM_UNDEFINED;
+
+ /* now: sc && sc->line_l () == line */
+ if (!line
+ || (sc->common_refpoint (line, X_AXIS)
+ && sc->common_refpoint (line, Y_AXIS)))
+ {
+ return sc->self_scm ();
+ }
+ return SCM_UNDEFINED;
+ }
+ }
+ else if (gh_pair_p (src))
+ {
+ SCM oldcar =gh_car (src);
+ /*
+ UGH! breaks on circular lists.
+ */
+ SCM newcar = handle_broken_smobs (oldcar, criterion);
+ SCM oldcdr = gh_cdr (src);
+
+ if (newcar == SCM_UNDEFINED
+ && (gh_pair_p (oldcdr) || oldcdr == SCM_EOL))
+ {
+ /*
+ This is tail-recursion, ie.
+
+ return handle_broken_smobs (cdr, criterion);
+
+ We don't want to rely on the compiler to do this. Without
+ tail-recursion, this easily crashes with a stack overflow. */
+ src = oldcdr;
+ goto again;
+ }
+
+ SCM newcdr = handle_broken_smobs (oldcdr, criterion);
+ return gh_cons (newcar, newcdr);
+ }
+ else
+ return src;
+
+ return src;