* consist of alnums and '-'. We don't permit whitespace between the '@'
* and the name. */
dynstr_init(d);
- if(input == end || !isalnum((unsigned char)*input))
- fatal(0, "%s:%d: invalid expansion", filename, e->line);
+ if(input == end)
+ fatal(0, "%s:%d: invalid expansion syntax (truncated)",
+ filename, e->line);
+ if(!isalnum((unsigned char)*input))
+ fatal(0, "%s:%d: invalid expansion syntax (unexpected %#x)",
+ filename, e->line, (unsigned char)*input);
while(input < end && (isalnum((unsigned char)*input) || *input == '-'))
dynstr_append(d, *input++);
dynstr_terminate(d);
*/
const struct mx_node *mx_rewrite(const struct mx_node *definition,
hash *h) {
- const struct mx_node *head = 0, **tailp = &head, *argvalue, *m, *mm;
+ const struct mx_node *head = 0, **tailp = &head, *argvalue, *m, *mm, **ap;
struct mx_node *nm;
int n;
break;
case MX_EXPANSION:
if(m->nargs == 0
- && (argvalue = *(const struct mx_node **)hash_find(h, m->name))) {
+ && (ap = hash_find(h, m->name))) {
/* This expansion has no arguments and its name matches one of the
* macro arguments. (Even if it's a valid expansion name we override
* it.) We insert its value at this point. We do NOT recursively
* We need to recreate the list structure but a shallow copy will
* suffice here.
*/
+ argvalue = *ap;
for(mm = argvalue; mm; mm = mm->next) {
nm = xmalloc(sizeof *nm);
*nm = *mm;
* @param name Base name of template, or NULL to consult CGI args
*/
void dcgi_expand(const char *name) {
- const char *p;
+ const char *p, *found;
/* Parse macros first */
- mx_expand_file("macros.tmpl", sink_discard(), 0);
+ if((found = mx_find("macros.tmpl")))
+ mx_expand_file(found, sink_discard(), 0);
/* For unknown actions check that they aren't evil */
for(p = name; *p && isalnum((unsigned char)*p); ++p)
;
if(*p)
fatal(0, "invalid action name '%s'", name);
byte_xasprintf((char **)&p, "%s.tmpl", name);
- if(mx_expand_file(p, sink_stdio("stdout", stdout), 0) == -1
+ if(!(found = mx_find(p)))
+ fatal(errno, "cannot find %s", p);
+ if(mx_expand_file(found, sink_stdio("stdout", stdout), 0) == -1
|| fflush(stdout) < 0)
fatal(errno, "error writing to stdout");
}
else
return 0;
}
+ fprintf(stderr, "track=[%s] part=[%s] context=[%s] dcgi_client=[%p]\n",
+ track,
+ part,
+ !strcmp(context, "short") ? "display" : context,
+ dcgi_client);
if(dcgi_client
&& !disorder_part(dcgi_client, &s,
track,
* - @display to the UNQUOTED display string for this track
*/
static int exp_search(int nargs,
- const struct mx_node **args,
- struct sink *output,
- void *u) {
+ const struct mx_node **args,
+ struct sink *output,
+ void *u) {
return exp__files_dirs(nargs, args, output, u, "track", exp__search_shim);
}
+static int exp_label(int attribute((unused)) nargs,
+ char **args,
+ struct sink *output,
+ void attribute((unused)) *u) {
+ return sink_writes(output, option_label(args[0])) < 0 ? -1 : 0;
+}
+
/** @brief Register DisOrder-specific expansions */
void dcgi_expansions(void) {
mx_register("arg", 1, 1, exp_arg);
mx_register("image", 1, 1, exp_image);
mx_register("isnew", 0, 0, exp_isnew);
mx_register("isplaying", 0, 0, exp_isplaying);
- mx_register("isplaying", 0, 0, exp_isqueue);
+ mx_register("isqueue", 0, 0, exp_isqueue);
mx_register("isrecent", 0, 0, exp_isrecent);
+ mx_register("label", 1, 1, exp_label);
mx_register("length", 1, 1, exp_length);
- mx_register("movable", 1, 1, exp_movable);
+ mx_register("movable", 1, 2, exp_movable);
mx_register("part", 2, 3, exp_part);
mx_register("paused", 0, 0, exp_paused);
mx_register("pref", 2, 2, exp_pref);
*/
const char *option_label(const char *key) {
const char *label;
+ char **lptr;
option__init();
- if(!(label = *(char **)hash_find(labels, key))) {
- /* No label found */
- if(!strncmp(key, "images.", 7)) {
- static const char *url_static;
- /* images.X defaults to <url.static>X.png */
-
- if(!url_static)
- url_static = option_label("url.static");
- byte_xasprintf((char **)&label, "%s%s.png", url_static, key + 7);
- } else if((label = strrchr(key, '.')))
- /* X.Y defaults to Y */
- ++label;
- else
- /* otherwise default to label name */
- label = key;
- }
+ lptr = hash_find(labels, key);
+ if(lptr)
+ return *lptr;
+ /* No label found */
+ if(!strncmp(key, "images.", 7)) {
+ static const char *url_static;
+ /* images.X defaults to <url.static>X.png */
+
+ if(!url_static)
+ url_static = option_label("url.static");
+ byte_xasprintf((char **)&label, "%s%s.png", url_static, key + 7);
+ } else if((label = strrchr(key, '.')))
+ /* X.Y defaults to Y */
+ ++label;
+ else
+ /* otherwise default to label name */
+ label = key;
return label;
}
@stdmenu{choose}
<h1>@label:choose.title@</h1>
- @if{@eq{@label{sidebar.choosewhich}}{choosealpha}}
+ @if{@eq{@label{menu.choosewhich}}{choosealpha}}
{
<p class=choosealpha>
<a title="Directories starting with 'a'"
@# Non-displaying <head> text
@define {quiethead} {}
- {<link rel=stylesheet
- type="text/css"
- href="@label{url.static}/disorder.css">}
+ { <link rel=stylesheet
+ type="text/css"
+ href="@label{url.static}/disorder.css">}
@# Standard menu
@# @current is the name of the current page, e.g. choosealpha, login
@define {stdmenu} {current}
- {<p class=menubar>
+ { <p class=menubar>
@menuitem{@current}{playing}{true}
+@menuitem{@current}{recent}{true}
@menuitem{@current}{choose}{@right{play}}
@menuitem{@current}{manage}{true}
@menuitem{@current}{login}{true}
@menuitem{@current}{help}{true}
@menuitem{@current}{about}{true}
-</p>
-<hr>
+ </p>
+ <hr>
}
@# Menu entry
@#
@define {menuitem} {current name available}
{@if{@available}
- { <a @if{@eq{@current}{@name}}
- {class=activemenu}
- {class=inactivemenu}
- @if{@eq{name}{playing}}
- {href="@url"}
- {href="@url?action=@name"}
- title="@label{menu.@q{@name}verbose}"
- @label{menu.@name}</a>}
- { <span class=invaldmenu title="@label{menu.@q{@name}verbose}">
- @label{menu.@name}</span>}}
+ { <a @if{@eq{@current}{@name}}
+ {class=activemenu}
+ {class=inactivemenu}
+@if{@eq{name}{playing}}
+ { href="@url"}
+ { href="@url?action=@name"}
+ title="@label{menu.@q{@name}verbose}">@label{menu.@name}</a>}
+ { <span class=invalidmenu
+ title="@label{menu.@q{@name}verbose}">@label{menu.@name}</span>}}
@# Standard footer text
{@right{play}
{<a class=directory
href="@url?action=choose&directory=@urlquote{@dirname{@dirname{@track}}}"
- title="@label{@what.artistverbose}">@part{@track}{short}{artist}</a>}
+ title="@label{@what.artistverbose}">@part{@track}{artist}{short}</a>}
{<span class=directory
- title="@part{@track}{artist}@">@part{@track}{short}{artist}</span>}}
+ title="@part{@track}{artist}">@part{@track}{artist}{short}</span>}}
@# Expand to the album for @track
@# @what is the section
{@right{play}
{<a class=directory
href="@url?action=choose&directory=@urlquote{@dirname{@track}}"
- title="@label{@what.albumverbose}">@part{@track}{short}{album}</a>}
+ title="@label{@what.albumverbose}">@part{@track}{album}{short}</a>}
{<span class=directory
- title="@part{@track}{album}@">@part{@track}{short}{album}</span>}}
+ title="@part{@track}{album}">@part{@track}{album}{short}</span>}}
@# Expand to the title for @track
@# @what is the section
@# @track is the track name
@define {mtitle} {what track}
- {<span title="@part{@track}{title}">@part{@track}{short}{title}</span>}
+ {<span title="@part{@track}{title}">@part{@track}{title}{short}</span>}
@# Expand to the remove/scratch entry for @id
@# @what is the section
# Text appended to all error pages
label error.generic ""
-# Displayed text for links in the sidebar (or other menu)
-label sidebar.playing Playing
-label sidebar.choose Choose
-label sidebar.random Random
-label sidebar.search Search
-label sidebar.recent Recent
-label sidebar.new New
-label sidebar.about About
-label sidebar.volume Volume
-label sidebar.login Login
-label sidebar.help Help
-label sidebar.manage Manage
-
-# Long (i.e. TITLE=) text for sidebar links
-label sidebar.playingverbose "Current and queued tracks"
-label sidebar.chooseverbose "Choose tracks"
-label sidebar.searchverbose "Word search among track names"
-label sidebar.recentverbose "Recently played tracks"
-label sidebar.newverbose "Newly added tracks"
-label sidebar.aboutverbose "About DisOrder"
-label sidebar.volumeverbose "Volume control"
-label sidebar.loginverbose "Log in to DisOrder"
-label sidebar.helpverbose "Basic user guide"
-label sidebar.manageverbose "Queue management and volume control"
+# Displayed text for links in the menu
+label menu.playing Playing
+label menu.choose Choose
+label menu.random Random
+label menu.search Search
+label menu.recent Recent
+label menu.new New
+label menu.about About
+label menu.volume Volume
+label menu.login Login
+label menu.help Help
+label menu.manage Manage
+
+# Long (i.e. TITLE=) text for menu links
+label menu.playingverbose "Current and queued tracks"
+label menu.chooseverbose "Choose tracks"
+label menu.searchverbose "Word search among track names"
+label menu.recentverbose "Recently played tracks"
+label menu.newverbose "Newly added tracks"
+label menu.aboutverbose "About DisOrder"
+label menu.volumeverbose "Volume control"
+label menu.loginverbose "Log in to DisOrder"
+label menu.helpverbose "Basic user guide"
+label menu.manageverbose "Queue management and volume control"
# This should be 'choose' or 'choosealpha'. If 'choose' then all artists
# appear on the same page, otherwise they are broken up by initial letter
# (which can be more convenient if you have huge numbers).
-label sidebar.choosewhich choose
+label menu.choosewhich choose
# Column headings for tables of tracks (playing, queue, recent)
label heading.when When
label images.noupall noupup.png
label images.downall downdown.png
label images.nodownall nodowndown.png
+
+# Where to find images etc
+label url.static /disorder
@# @state should be the current state
@define {onoff} {class action state}
{<a class=button
- href="@url?action=@action@back"@class}@q{@state
+ href="@url?action=@action@back"
title="@label{playing.@q{action}verbose}">
@label{playing.@class}
</a>
<input size=3 name=left type=text value="@volume{left}">
@label{volume.right}
<input size=3 name=right type=text value="@volume{right}">
- <input name=back type=hidden value="@thisurl@?back=manage">
+ <input name=back type=hidden value="@thisurl?back=manage">
@right{volume}{
<button class=search name=submit type=submit>
@label{volume.set}
}{}
</tr>
}
- @if{@isqueue@}{
- <tr class=next>
- <td colspan=@ifmanage{11}{7}@>@label{playing.next}</td>
- </tr>
+ @if{@isqueue}{
+ <tr class=next>
+ <td colspan=@ifmanage{11}{7}>@label{playing.next}</td>
+ </tr>
}
@queue{
- <tr class=@parity@>
- <td class=when>@mwhen{queue}{@id}</td>
- <td class=who>@mwho{queue}{@id}</td>
- <td class=artist>@martist{queue}{@track}</td>
- <td class=album>@malbum{queue}{@track}</td>
- <td class=title>@mtitle{queue}{@track}</td>
- <td class=length>@length</td>
- <td class=imgbutton>@mremove{queue}{@id}</td>
- @ifmanage{
- <td class=imgbutton>@mmove{@id}{upall}{2147483647}</td>
- <td class=imgbutton>@mmove{@id}{up}{1}</td>
- <td class=imgbutton>@mmove{@id}{down}{-1}</td>
- <td class=imgbutton>@mmove{@id}{downall}{-2147483647}</td>
- }
- </tr>
- }
+ <tr class=@parity>
+ <td class=when>@mwhen{queue}{@id}</td>
+ <td class=who>@mwho{queue}{@id}</td>
+ <td class=artist>@martist{queue}{@track}</td>
+ <td class=album>@malbum{queue}{@track}</td>
+ <td class=title>@mtitle{queue}{@track}</td>
+ <td class=length>@length{@id}</td>
+ <td class=imgbutton>@mremove{queue}{@id}</td>
+ @ifmanage{
+ <td class=imgbutton>@mmove{@id}{upall}{2147483647}</td>
+ <td class=imgbutton>@mmove{@id}{up}{1}</td>
+ <td class=imgbutton>@mmove{@id}{down}{-1}</td>
+ <td class=imgbutton>@mmove{@id}{downall}{-2147483647}</td>
+ }{}
+ </tr>
+ }
</table>
}
</tr>
<tr class=even>
<td class="prefs_name">@label:heading.title@</td>
- <td class="prefs_value"><input size=40 type=text name="@index@_title" value="@part{display}{title}{@arg{@index@_file}@}@"></td>
+ <td class="prefs_value"><input size=40 type=text name="@index@_title" value="@part{@arg{@index@_file}display}{title}{display}"></td>
</tr>
<tr class=odd>
<td class="prefs_name">@label:heading.album@</td>