+ if (r == NULL || r->ws == NULL)
+ return;
+ if (r->ws->name != NULL)
+ strlcat(s, r->ws->name, sz);
+}
+
+/* build the default bar format according to the defined enabled options */
+void
+bar_fmt(const char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz)
+{
+ /* if format provided, just copy the buffers */
+ if (bar_format != NULL) {
+ strlcpy(fmtnew, fmtexp, sz);
+ return;
+ }
+
+ /* reset the output buffer */
+ *fmtnew = '\0';
+
+ strlcat(fmtnew, "+N:+I ", sz);
+ if (stack_enabled)
+ strlcat(fmtnew, "+S", sz);
+ strlcat(fmtnew, " ", sz);
+
+ /* only show the workspace name if there's actually one */
+ if (r != NULL && r->ws != NULL && r->ws->name != NULL)
+ strlcat(fmtnew, "<+D>", sz);
+ strlcat(fmtnew, "+3<", sz);
+
+ if (clock_enabled) {
+ strlcat(fmtnew, fmtexp, sz);
+ strlcat(fmtnew, "+4<", sz);
+ }
+
+ /* bar_urgent already adds the space before the last asterisk */
+ if (urgent_enabled)
+ strlcat(fmtnew, "* +U*+4<", sz);
+
+ if (title_class_enabled) {
+ strlcat(fmtnew, "+C", sz);
+ if (title_name_enabled == 0)
+ strlcat(fmtnew, "+4<", sz);
+ }
+
+ /* checks needed by the colon and floating strlcat(3) calls below */
+ if (r != NULL && r->ws != NULL && r->ws->focus != NULL) {
+ if (title_name_enabled) {
+ if (title_class_enabled)
+ strlcat(fmtnew, ":", sz);
+ strlcat(fmtnew, "+T+4<", sz);
+ }
+ if (window_name_enabled) {
+ if (r->ws->focus->floating)
+ strlcat(fmtnew, "+F ", sz);
+ strlcat(fmtnew, "+64W ", sz);
+ }
+ }
+
+ /* finally add the action script output and the version */
+ strlcat(fmtnew, "+4<+A+4<+V", sz);
+}
+
+void
+bar_replace_pad(char *tmp, int *limit, size_t sz)
+{
+ /* special case; no limit given, pad one space, instead */
+ if (*limit == sz - 1)
+ *limit = 1;
+ snprintf(tmp, sz, "%*s", *limit, " ");
+}
+
+/* replaces the bar format character sequences (like in tmux(1)) */
+char *
+bar_replace_seq(char *fmt, char *fmtrep, struct swm_region *r, size_t *offrep,
+ size_t sz)
+{
+ char *ptr;
+ char tmp[SWM_BAR_MAX];
+ int limit, size;
+ size_t len;
+
+ /* reset strlcat(3) buffer */
+ *tmp = '\0';
+
+ /* get number, if any */
+ fmt++;
+ size = 0;
+ if (sscanf(fmt, "%d%n", &limit, &size) != 1)
+ limit = sizeof tmp - 1;
+ if (limit <= 0 || limit >= sizeof tmp)
+ limit = sizeof tmp - 1;
+
+ /* there is nothing to replace (ie EOL) */
+ fmt += size;
+ if (*fmt == '\0')
+ return (fmt);
+
+ switch (*fmt) {
+ case '<':
+ bar_replace_pad(tmp, &limit, sizeof tmp);
+ break;
+ case 'A':
+ snprintf(tmp, sizeof tmp, "%s", bar_ext);
+ break;
+ case 'C':
+ bar_class_name(tmp, sizeof tmp, r);
+ break;
+ case 'D':
+ bar_workspace_name(tmp, sizeof tmp, r);
+ break;
+ case 'F':
+ bar_window_float(tmp, sizeof tmp, r);
+ break;
+ case 'I':
+ snprintf(tmp, sizeof tmp, "%d", r->ws->idx + 1);
+ break;
+ case 'N':
+ snprintf(tmp, sizeof tmp, "%d", r->s->idx + 1);
+ break;
+ case 'P':
+ bar_class_title_name(tmp, sizeof tmp, r);
+ break;
+ case 'S':
+ snprintf(tmp, sizeof tmp, "%s", r->ws->stacker);
+ break;
+ case 'T':
+ bar_title_name(tmp, sizeof tmp, r);
+ break;
+ case 'U':
+ bar_urgent(tmp, sizeof tmp);
+ break;
+ case 'V':
+ snprintf(tmp, sizeof tmp, "%s", bar_vertext);
+ break;
+ case 'W':
+ bar_window_name(tmp, sizeof tmp, r);
+ break;
+ default:
+ /* unknown character sequence; copy as-is */
+ snprintf(tmp, sizeof tmp, "+%c", *fmt);
+ break;
+ }
+
+ len = strlen(tmp);
+ ptr = tmp;
+ if (len < limit)
+ limit = len;
+ while (limit-- > 0) {
+ if (*offrep >= sz - 1)
+ break;
+ fmtrep[(*offrep)++] = *ptr++;
+ }
+
+ fmt++;
+ return (fmt);
+}
+
+void
+bar_replace(char *fmt, char *fmtrep, struct swm_region *r, size_t sz)
+{
+ size_t off;
+
+ off = 0;
+ while (*fmt != '\0') {
+ if (*fmt != '+') {
+ /* skip ordinary characters */
+ if (off >= sz - 1)
+ break;
+ fmtrep[off++] = *fmt++;
+ continue;
+ }
+
+ /* character sequence found; replace it */
+ fmt = bar_replace_seq(fmt, fmtrep, r, &off, sz);
+ if (off >= sz - 1)
+ break;
+ }
+
+ fmtrep[off] = '\0';
+}
+
+void
+bar_fmt_expand(char *fmtexp, size_t sz)
+{
+ char *fmt = NULL;
+ size_t len;