$QUERY bug
The following explanation came from @dlw :
So, $query works by doing one of two operations. Say you have data that looks like this:
a=5
a(1)=1
a(1,2)=12
a(2,1)=21
a("a")="a"
a("a","b")="ab"
For this terminology, a branch is a horizontal line of the array, as illustrated in the example data, and a level is a vertical line of the array, within a single branch. So $order would move from branch to branch, while adding subscripts to a particular branch would be moving through levels.
From the top node, it will first go down a branch. Visually, going down a branch would be like going from a(1) to a(2). Then, it will go across the branch towards the leaves, changing levels. Visually, going across the branch, changing levels, would be like going from a(1) to a(1,2). Every time it makes a move like that, it checks to make sure there is data at that node, and if there isn't, it makes another move. That is the basic algorithm. Each time data is found, it will return to xecline to write it to the screen.
So this algorithm works fine in most cases, but where it breaks is when moving to a new branch, which has no data on the same level as the previous branch it came from, such as a(2,1) from the example data. There is no data at a(2). The algorithm will move from a(1,2) to a(2), as it should, but because there is no data there, it will immediately move on to a("a"), skipping the level move to a(2,1), thus omitting a(2,1)=21 from the output. So, here is the code where that happens, symtab.c:1335:
/* If that fails, look for the next entry */
while(!get && loc_last->parent) {
get = get_next(loc_last->branch, loc_last->parent);
while(get && !DATA(get)) {
get = get_next(get, loc_last->parent);
if(get && !DATA(get)) {
loc_tmp = get_first_string(get->rc->subs, &get, NULL);
if (loc_tmp == NULL) {
ierr = SBSCR;
return;
}
if(get && DATA(get)) {
loc_last->child = loc_tmp;
loc_tmp->parent = loc_last;
while(loc_last->child) loc_last = loc_last->child;
}
}
}
loc_tmp = loc_last; loc_last = loc_last->parent;
loc_last->child = NULL; free(loc_tmp);
}
So, to get in to that while loop, get has to be NULL, and previous attempts to get the next node of data didn't work. So the first call to get the next branch get = get_next(loc_last->branch, loc_last->parent); works and moves you from a(1,2) to a(2). However, the problem is that it then checks for data, and doesn't find any, but instead of moving down the levels of the branch to check for data, like it should, it calls get = get_next(get, loc_last->parent); again, which then moves a(2) to a("a"), skipping the node that had data at a(2,1). This does not happen when the first node on a branch has data, as it won't call get_next twice in a row like that. This is not just an issue with zwrite, if you call $query(a(1,2)) it will return a("a") as well. So, $query will always skip nodes that are at a higher level than the branch, if the lower level of the branch doesn't also have data.
Make sense?
USER [LEGACY]> s abc(1)=1,abc(1,2)="one",abc(2,"two")="two",abc("a string")="quotes",abc("a string",10)=10
USER [LEGACY]> zwrite abc
abc=
abc(1)=1
abc(1,2)=one
abc(a string)=quotes
abc(a string,10)=10
USER [LEGACY]> w $q(abc(1,2))
abc(a string)
USER [LEGACY]> w abc(2,"two")
two
USER [LEGACY]>