+struct sortstr
+{
+ Lisp_Object string, string2;
+ int size;
+ int priority;
+};
+
+struct sortstrlist
+{
+ struct sortstr *buf; /* An array that expands as needed; never freed. */
+ int size; /* Allocated length of that array. */
+ int used; /* How much of the array is currently in use. */
+ int bytes; /* Total length of the strings in buf. */
+};
+
+/* Buffers for storing information about the overlays touching a given
+ position. These could be automatic variables in overlay_strings, but
+ it's more efficient to hold onto the memory instead of repeatedly
+ allocating and freeing it. */
+static struct sortstrlist overlay_heads, overlay_tails;
+static char *overlay_str_buf;
+
+/* Allocated length of overlay_str_buf. */
+static int overlay_str_len;
+
+/* A comparison function suitable for passing to qsort. */
+static int
+cmp_for_strings (as1, as2)
+ char *as1, *as2;
+{
+ struct sortstr *s1 = (struct sortstr *)as1;
+ struct sortstr *s2 = (struct sortstr *)as2;
+ if (s1->size != s2->size)
+ return s2->size - s1->size;
+ if (s1->priority != s2->priority)
+ return s1->priority - s2->priority;
+ return 0;
+}
+
+static void
+record_overlay_string (ssl, str, str2, pri, size)
+ struct sortstrlist *ssl;
+ Lisp_Object str, str2, pri;
+ int size;
+{
+ if (ssl->used == ssl->size)
+ {
+ if (ssl->buf)
+ ssl->size *= 2;
+ else
+ ssl->size = 5;
+ ssl->buf = ((struct sortstr *)
+ xrealloc (ssl->buf, ssl->size * sizeof (struct sortstr)));
+ }
+ ssl->buf[ssl->used].string = str;
+ ssl->buf[ssl->used].string2 = str2;
+ ssl->buf[ssl->used].size = size;
+ ssl->buf[ssl->used].priority = (INTEGERP (pri) ? XINT (pri) : 0);
+ ssl->used++;
+ ssl->bytes += XSTRING (str)->size;
+ if (STRINGP (str2))
+ ssl->bytes += XSTRING (str2)->size;
+}
+
+/* Return the concatenation of the strings associated with overlays that
+ begin or end at POS, ignoring overlays that are specific to a window
+ other than W. The strings are concatenated in the appropriate order:
+ shorter overlays nest inside longer ones, and higher priority inside
+ lower. Normally all of the after-strings come first, but zero-sized
+ overlays have their after-strings ride along with the before-strings
+ because it would look strange to print them inside-out.
+
+ Returns the string length, and stores the contents indirectly through
+ PSTR, if that variable is non-null. The string may be overwritten by
+ subsequent calls. */
+int
+overlay_strings (pos, w, pstr)
+ int pos;
+ struct window *w;
+ char **pstr;
+{
+ Lisp_Object ov, overlay, window, str;
+ int startpos, endpos;
+
+ overlay_heads.used = overlay_heads.bytes = 0;
+ overlay_tails.used = overlay_tails.bytes = 0;
+ for (ov = current_buffer->overlays_before; CONSP (ov); ov = XCONS (ov)->cdr)
+ {
+ overlay = XCONS (ov)->car;
+ if (!OVERLAYP (overlay))
+ abort ();
+
+ startpos = OVERLAY_POSITION (OVERLAY_START (overlay));
+ endpos = OVERLAY_POSITION (OVERLAY_END (overlay));
+ if (endpos < pos)
+ break;
+ if (endpos != pos && startpos != pos)
+ continue;
+ window = Foverlay_get (overlay, Qwindow);
+ if (WINDOWP (window) && XWINDOW (window) != w)
+ continue;
+ if (startpos == pos
+ && (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str)))
+ record_overlay_string (&overlay_heads, str,
+ (startpos == endpos
+ ? Foverlay_get (overlay, Qafter_string)
+ : Qnil),
+ Foverlay_get (overlay, Qpriority),
+ endpos - startpos);
+ else if (endpos == pos
+ && (str = Foverlay_get (overlay, Qafter_string), STRINGP (str)))
+ record_overlay_string (&overlay_tails, str, Qnil,
+ Foverlay_get (overlay, Qpriority),
+ endpos - startpos);
+ }
+ for (ov = current_buffer->overlays_after; CONSP (ov); ov = XCONS (ov)->cdr)
+ {
+ overlay = XCONS (ov)->car;
+ if (!OVERLAYP (overlay))
+ abort ();
+
+ startpos = OVERLAY_POSITION (OVERLAY_START (overlay));
+ endpos = OVERLAY_POSITION (OVERLAY_END (overlay));
+ if (startpos > pos)
+ break;
+ if (endpos != pos && startpos != pos)
+ continue;
+ window = Foverlay_get (overlay, Qwindow);
+ if (WINDOWP (window) && XWINDOW (window) != w)
+ continue;
+ if (startpos == pos
+ && (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str)))
+ record_overlay_string (&overlay_heads, str,
+ (startpos == endpos
+ ? Foverlay_get (overlay, Qafter_string)
+ : Qnil),
+ Foverlay_get (overlay, Qpriority),
+ endpos - startpos);
+ else if (endpos == pos
+ && (str = Foverlay_get (overlay, Qafter_string), STRINGP (str)))
+ record_overlay_string (&overlay_tails, str, Qnil,
+ Foverlay_get (overlay, Qpriority),
+ endpos - startpos);
+ }
+ if (overlay_tails.used > 1)
+ qsort (overlay_tails.buf, overlay_tails.used, sizeof (struct sortstr),
+ cmp_for_strings);
+ if (overlay_heads.used > 1)
+ qsort (overlay_heads.buf, overlay_heads.used, sizeof (struct sortstr),
+ cmp_for_strings);
+ if (overlay_heads.bytes || overlay_tails.bytes)
+ {
+ Lisp_Object tem;
+ int i;
+ char *p;
+ int total = overlay_heads.bytes + overlay_tails.bytes;
+
+ if (total > overlay_str_len)
+ overlay_str_buf = (char *)xrealloc (overlay_str_buf,
+ overlay_str_len = total);
+ p = overlay_str_buf;
+ for (i = overlay_tails.used; --i >= 0;)
+ {
+ tem = overlay_tails.buf[i].string;
+ bcopy (XSTRING (tem)->data, p, XSTRING (tem)->size);
+ p += XSTRING (tem)->size;
+ }
+ for (i = 0; i < overlay_heads.used; ++i)
+ {
+ tem = overlay_heads.buf[i].string;
+ bcopy (XSTRING (tem)->data, p, XSTRING (tem)->size);
+ p += XSTRING (tem)->size;
+ tem = overlay_heads.buf[i].string2;
+ if (STRINGP (tem))
+ {
+ bcopy (XSTRING (tem)->data, p, XSTRING (tem)->size);
+ p += XSTRING (tem)->size;
+ }
+ }
+ if (p != overlay_str_buf + total)
+ abort ();
+ if (pstr)
+ *pstr = overlay_str_buf;
+ return total;
+ }
+ return 0;
+}
+\f