cvs -z3 -d:pserver:anonymous@libmigdb.cvs.sourceforge.net:/cvsroot/libmigdb co -P...
[gdbmicli.git] / libmigdb / src / parse.c
1 /**[txh]********************************************************************
2
3   Copyright (c) 2004-2007 by Salvador E. Tropea.
4   Covered by the GPL license.
5
6   Module: Parser.
7   Comments:
8   Parses the output of gdb. It basically converts the text from gdb into a
9 tree (could be a complex one) that we can easily interpret using C code.
10   
11 ***************************************************************************/
12
13 #include <ctype.h>
14 #include <string.h>
15 #include <assert.h>
16 #include "mi_gdb.h"
17
18 mi_results *mi_get_result(const char *str, const char **end);
19 int mi_get_value(mi_results *r, const char *str, const char **end);
20
21
22 /* GDB BUG!!!! I got:
23 ^error,msg="Problem parsing arguments: data-evaluate-expression ""1+2"""
24 Afects gdb 2002-04-01-cvs and 6.1.1 for sure.
25 That's an heuristical workaround.
26 */
27 static inline
28 int EndOfStr(const char *s)
29 {
30  if (*s=='"')
31    {
32     s++;
33     return !*s || *s==',' || *s==']' || *s=='}';
34    }
35  return 0;
36 }
37
38 int mi_get_cstring_r(mi_results *r, const char *str, const char **end)
39 {
40  const char *s;
41  char *d;
42  int len;
43
44  if (*str!='"')
45    {
46     mi_error=MI_PARSER;
47     return 0;
48    }
49  str++;
50  /* Meassure. */
51  for (s=str, len=0; *s && !EndOfStr(s); s++)
52     {
53      if (*s=='\\')
54        {
55         if (!*s)
56           {
57            mi_error=MI_PARSER;
58            return 0;
59           }
60         s++;
61        }
62      len++;
63     }
64  /* Copy. */
65  r->type=t_const;
66  d=r->v.cstr=mi_malloc(len+1);
67  if (!r->v.cstr)
68     return 0;
69  for (s=str; *s && !EndOfStr(s); s++, d++)
70     {
71      if (*s=='\\')
72        {
73         s++;
74         switch (*s)
75           {
76            case 'n':
77                 *d='\n';
78                 break;
79            case 't':
80                 *d='\t';
81                 break;
82            default:
83                 *d=*s;
84           }
85        }
86      else
87         *d=*s;
88     }
89  *d=0;
90  if (end)
91     *end=s+1;
92
93  return 1;
94 }
95
96 /* TODO: What's a valid variable name?
97    I'll assume a-zA-Z0-9_- */
98 inline
99 int mi_is_var_name_char(char c)
100 {
101  return isalnum(c) || c=='-' || c=='_';
102 }
103
104 char *mi_get_var_name(const char *str, const char **end)
105 {
106  const char *s;
107  char *r;
108  int l;
109  /* Meassure. */
110  for (s=str; *s && mi_is_var_name_char(*s); s++);
111  if (*s!='=')
112    {
113     mi_error=MI_PARSER;
114     return NULL;
115    }
116  /* Allocate. */
117  l=s-str;
118  r=mi_malloc(l+1);
119  /* Copy. */
120  memcpy(r,str,l);
121  r[l]=0;
122  if (end)
123     *end=s+1;
124  return r;
125 }
126
127
128 int mi_get_list_res(mi_results *r, const char *str, const char **end, char closeC)
129 {
130  mi_results *last_r, *rs;
131
132  last_r=NULL;
133  do
134    {
135     rs=mi_get_result(str,&str);
136     if (last_r)
137        last_r->next=rs;
138     else
139        r->v.rs=rs;
140     last_r=rs;
141     if (*str==closeC)
142       {
143        *end=str+1;
144        return 1;
145       }
146     if (*str!=',')
147        break;
148     str++;
149    }
150  while (1);
151
152  mi_error=MI_PARSER;
153  return 0;
154 }
155
156 #ifdef __APPLE__
157 int mi_get_tuple_val(mi_results *r, const char *str, const char **end)
158 {
159  mi_results *last_r, *rs;
160
161  last_r=NULL;
162  do
163    {
164     rs=mi_alloc_results();
165     if (!rs || !mi_get_value(rs,str,&str))
166       {
167        mi_free_results(rs);
168        return 0;
169       }
170     /* Note that rs->var is NULL, that indicates that's just a value and not
171        a result. */
172     if (last_r)
173        last_r->next=rs;
174     else
175        r->v.rs=rs;
176     last_r=rs;
177     if (*str=='}')
178       {
179        *end=str+1;
180        return 1;
181       }
182     if (*str!=',')
183        break;
184     str++;
185    }
186  while (1);
187
188  mi_error=MI_PARSER;
189  return 0;
190 }
191 #endif /* __APPLE__ */
192
193 int mi_get_tuple(mi_results *r, const char *str, const char **end)
194 {
195  if (*str!='{')
196    {
197     mi_error=MI_PARSER;
198     return 0;
199    }
200  r->type=t_tuple;
201  str++;
202  if (*str=='}')
203    {/* Special case: empty tuple */
204     *end=str+1;
205     return 1;
206    }
207  #ifdef __APPLE__
208  if (mi_is_var_name_char(*str))
209     return mi_get_list_res(r,str,end,'}');
210  return mi_get_tuple_val(r,str,end);
211  #else /* __APPLE__ */
212  return mi_get_list_res(r,str,end,'}');
213  #endif /* __APPLE__ */
214 }
215
216 int mi_get_list_val(mi_results *r, const char *str, const char **end)
217 {
218  mi_results *last_r, *rs;
219
220  last_r=NULL;
221  do
222    {
223     rs=mi_alloc_results();
224     if (!rs || !mi_get_value(rs,str,&str))
225       {
226        mi_free_results(rs);
227        return 0;
228       }
229     /* Note that rs->var is NULL, that indicates that's just a value and not
230        a result. */
231     if (last_r)
232        last_r->next=rs;
233     else
234        r->v.rs=rs;
235     last_r=rs;
236     if (*str==']')
237       {
238        *end=str+1;
239        return 1;
240       }
241     if (*str!=',')
242        break;
243     str++;
244    }
245  while (1);
246
247  mi_error=MI_PARSER;
248  return 0;
249 }
250
251 int mi_get_list(mi_results *r, const char *str, const char **end)
252 {
253  if (*str!='[')
254    {
255     mi_error=MI_PARSER;
256     return 0;
257    }
258  r->type=t_list;
259  str++;
260  if (*str==']')
261    {/* Special case: empty list */
262     *end=str+1;
263     return 1;
264    }
265  /* Comment: I think they could choose () for values. Is confusing in this way. */
266  if (mi_is_var_name_char(*str))
267     return mi_get_list_res(r,str,end,']');
268  return mi_get_list_val(r,str,end);
269 }
270
271 int mi_get_value(mi_results *r, const char *str, const char **end)
272 {
273  switch (str[0])
274    {
275     case '"':
276          return mi_get_cstring_r(r,str,end);
277     case '{':
278          return mi_get_tuple(r,str,end);
279     case '[':
280          return mi_get_list(r,str,end);
281    }
282  mi_error=MI_PARSER;
283  return 0;
284 }
285
286 mi_results *mi_get_result(const char *str, const char **end)
287 {
288  char *var;
289  mi_results *r;
290
291  var=mi_get_var_name(str,&str);
292  if (!var)
293     return NULL;
294
295  r=mi_alloc_results();
296  if (!r)
297    {
298     free(var);
299     return NULL;
300    }
301  r->var=var;
302
303  if (!mi_get_value(r,str,end))
304    {
305     mi_free_results(r);
306     return NULL;
307    }
308
309  return r;
310 }
311
312 mi_output *mi_get_results_alone(mi_output *r,const char *str)
313 {
314  mi_results *last_r, *rs;
315
316  /* * results */
317  last_r=NULL;
318  do
319    {
320     if (!*str)
321        return r;
322     if (*str!=',')
323       {
324        mi_error=MI_PARSER;
325        break;
326       }
327     str++;
328     rs=mi_get_result(str,&str);
329     if (!rs)
330        break;
331     if (!last_r)
332        r->c=rs;
333     else
334        last_r->next=rs;
335     last_r=rs;
336    }
337  while (1);
338  mi_free_output(r);
339  return NULL;
340 }
341
342 mi_output *mi_parse_result_record(mi_output *r,const char *str)
343 {
344  r->type=MI_T_RESULT_RECORD;
345
346  /* Solve the result-class. */
347  if (strncmp(str,"done",4)==0)
348    {
349     str+=4;
350     r->tclass=MI_CL_DONE;
351    }
352  else if (strncmp(str,"running",7)==0)
353    {
354     str+=7;
355     r->tclass=MI_CL_RUNNING;
356    }
357  else if (strncmp(str,"connected",9)==0)
358    {
359     str+=9;
360     r->tclass=MI_CL_CONNECTED;
361    }
362  else if (strncmp(str,"error",5)==0)
363    {
364     str+=5;
365     r->tclass=MI_CL_ERROR;
366    }
367  else if (strncmp(str,"exit",4)==0)
368    {
369     str+=4;
370     r->tclass=MI_CL_EXIT;
371    }
372  else
373    {
374     mi_error=MI_UNKNOWN_RESULT;
375     return NULL;
376    }
377
378  return mi_get_results_alone(r,str);
379 }
380
381 mi_output *mi_parse_asyn(mi_output *r,const char *str)
382 {
383  r->type=MI_T_OUT_OF_BAND;
384  r->stype=MI_ST_ASYNC;
385  /* async-class. */
386  if (strncmp(str,"stopped",7)==0)
387    {
388     r->tclass=MI_CL_STOPPED;
389     str+=7;
390     return mi_get_results_alone(r,str);
391    }
392  if (strncmp(str,"download",8)==0)
393    {
394     r->tclass=MI_CL_DOWNLOAD;
395     str+=8;
396     return mi_get_results_alone(r,str);
397    }
398  mi_error=MI_UNKNOWN_ASYNC;
399  mi_free_output(r);
400  return NULL;
401 }
402
403 mi_output *mi_parse_exec_asyn(mi_output *r,const char *str)
404 {
405  r->sstype=MI_SST_EXEC;
406  return mi_parse_asyn(r,str);
407 }
408
409 mi_output *mi_parse_status_asyn(mi_output *r,const char *str)
410 {
411  r->sstype=MI_SST_STATUS;
412  return mi_parse_asyn(r,str);
413 }
414
415 mi_output *mi_parse_notify_asyn(mi_output *r,const char *str)
416 {
417  r->sstype=MI_SST_NOTIFY;
418  return mi_parse_asyn(r,str);
419 }
420
421 mi_output *mi_console(mi_output *r,const char *str)
422 {
423  r->type=MI_T_OUT_OF_BAND;
424  r->stype=MI_ST_STREAM;
425  r->c=mi_alloc_results();
426  if (!r->c || !mi_get_cstring_r(r->c,str,NULL))
427    {
428     mi_free_output(r);
429     return NULL;
430    }
431  return r;
432 }
433
434 mi_output *mi_console_stream(mi_output *r,const char *str)
435 {
436  r->sstype=MI_SST_CONSOLE;
437  return mi_console(r,str);
438 }
439
440 mi_output *mi_target_stream(mi_output *r,const char *str)
441 {
442  r->sstype=MI_SST_TARGET;
443  return mi_console(r,str);
444 }
445
446 mi_output *mi_log_stream(mi_output *r,const char *str)
447 {
448  r->sstype=MI_SST_LOG;
449  return mi_console(r,str);
450 }
451
452 mi_output *mi_parse_gdb_output(const char *str)
453 {
454  char type=str[0];
455
456  mi_output *r=mi_alloc_output();
457  if (!r)
458    {
459     mi_error=MI_OUT_OF_MEMORY;
460     return NULL;
461    }
462  str++;
463  switch (type)
464    {
465     case '^':
466          return mi_parse_result_record(r,str);
467     case '*':
468          return mi_parse_exec_asyn(r,str);
469     case '+':
470          return mi_parse_status_asyn(r,str);
471     case '=':
472          return mi_parse_notify_asyn(r,str);
473     case '~':
474          return mi_console_stream(r,str);
475     case '@':
476          return mi_target_stream(r,str);
477     case '&':
478          return mi_log_stream(r,str);
479    }   
480  mi_error=MI_PARSER;
481  return NULL;
482 }
483
484 mi_output *mi_get_rrecord(mi_output *r)
485 {
486  if (!r)
487     return NULL;
488  while (r)
489    {
490     if (r->type==MI_T_RESULT_RECORD)
491        return r;
492     r=r->next;
493    }
494  return r;
495 }
496
497 mi_results *mi_get_var_r(mi_results *r, const char *var)
498 {
499  while (r)
500    {
501     if (strcmp(r->var,var)==0)
502        return r;
503     r=r->next;
504    }
505  return NULL;
506 }
507
508 mi_results *mi_get_var(mi_output *res, const char *var)
509 {
510  if (!res)
511     return NULL;
512  return mi_get_var_r(res->c,var);
513 }
514
515 int mi_get_async_stop_reason(mi_output *r, char **reason)
516 {
517  int found_stopped=0;
518
519  *reason=NULL;
520  while (r)
521    {
522     if (r->type==MI_T_RESULT_RECORD && r->tclass==MI_CL_ERROR)
523       {
524        if (r->c->type==t_const)
525           *reason=r->c->v.cstr;
526        return 0;
527       }
528     if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
529         r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
530       {
531        mi_results *p=r->c;
532        found_stopped=1;
533        while (p)
534          {
535           if (strcmp(p->var,"reason")==0)
536             {
537              *reason=p->v.cstr;
538              return 1;
539             }
540           p=p->next;
541          }
542       }
543     r=r->next;
544    }
545  if (*reason==NULL && found_stopped)
546    {
547     *reason=strdup("unknown (temp bkpt?)");
548     return 1;
549    }
550  return 0;
551 }
552
553 mi_frames *mi_get_async_frame(mi_output *r)
554 {
555  while (r)
556    {
557     if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
558         r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
559       {
560        mi_results *p=r->c;
561        while (p)
562          {
563           if (strcmp(p->var,"frame")==0)
564              return mi_parse_frame(p->v.rs);
565           p=p->next;
566          }
567       }
568     r=r->next;
569    }
570  return NULL;
571 }
572
573 int mi_res_simple(mi_h *h, int tclass, int accert_ret)
574 {
575  mi_output *r, *res;
576  int ret=0;
577
578  r=mi_get_response_blk(h);
579  res=mi_get_rrecord(r);
580
581  if (res)
582     ret=res->tclass==tclass;
583  mi_free_output(r);
584
585  return ret;
586 }
587
588
589 int mi_res_simple_done(mi_h *h)
590 {
591  return mi_res_simple(h,MI_CL_DONE,0);
592 }
593
594 int mi_res_simple_exit(mi_h *h)
595 {
596  return mi_res_simple(h,MI_CL_EXIT,1);
597 }
598
599 int mi_res_simple_running(mi_h *h)
600 {
601  return mi_res_simple(h,MI_CL_RUNNING,0);
602 }
603
604 int mi_res_simple_connected(mi_h *h)
605 {
606  return mi_res_simple(h,MI_CL_CONNECTED,0);
607 }
608
609 mi_results *mi_res_var(mi_h *h, const char *var, int tclass)
610 {
611  mi_output *r, *res;
612  mi_results *the_var=NULL;
613
614  r=mi_get_response_blk(h);
615  /* All the code that follows is "NULL" tolerant. */
616  /* Look for the result-record. */
617  res=mi_get_rrecord(r);
618  /* Look for the desired var. */
619  if (res && res->tclass==tclass)
620     the_var=mi_get_var(res,var);
621  /* Release all but the one we want. */
622  mi_free_output_but(r,NULL,the_var);
623  return the_var;
624 }
625
626 mi_results *mi_res_done_var(mi_h *h, const char *var)
627 {
628  return mi_res_var(h,var,MI_CL_DONE);
629 }
630
631 mi_frames *mi_parse_frame(mi_results *c)
632 {
633  mi_frames *res=mi_alloc_frames();
634  char *end;
635
636  if (res)
637    {
638     while (c)
639       {
640        if (c->type==t_const)
641          {
642           if (strcmp(c->var,"level")==0)
643              res->level=atoi(c->v.cstr);
644           else if (strcmp(c->var,"addr")==0)
645              res->addr=(void *)strtoul(c->v.cstr,&end,0);
646           else if (strcmp(c->var,"func")==0)
647             {
648              res->func=c->v.cstr;
649              c->v.cstr=NULL;
650             }
651           else if (strcmp(c->var,"file")==0)
652             {
653              res->file=c->v.cstr;
654              c->v.cstr=NULL;
655             }
656           else if (strcmp(c->var,"from")==0)
657             {
658              res->from=c->v.cstr;
659              c->v.cstr=NULL;
660             }
661           else if (strcmp(c->var,"line")==0)
662              res->line=atoi(c->v.cstr);
663          }
664        else if (c->type==t_list && strcmp(c->var,"args")==0)
665          {
666           res->args=c->v.rs;
667           c->v.rs=NULL;
668          }
669        c=c->next;
670       }
671    }
672  return res;
673 }
674
675 mi_frames *mi_res_frame(mi_h *h)
676 {
677  mi_results *r=mi_res_done_var(h,"frame");
678  mi_frames *f=NULL;
679
680  if (r && r->type==t_tuple)
681     f=mi_parse_frame(r->v.rs);
682  mi_free_results(r);
683  return f;
684 }
685
686 mi_frames *mi_res_frames_array(mi_h *h, const char *var)
687 {
688  mi_results *r=mi_res_done_var(h,var), *c;
689  mi_frames *res=NULL, *nframe, *last=NULL;
690
691  if (!r)
692     return NULL;
693 #ifdef __APPLE__
694  if (r->type!=t_list && r->type!=t_tuple)
695 #else
696  if (r->type!=t_list)
697 #endif
698    {
699     mi_free_results(r);
700     return NULL;
701    }
702  c=r->v.rs;
703  while (c)
704    {
705     if (strcmp(c->var,"frame")==0 && c->type==t_tuple)
706       {
707        nframe=mi_parse_frame(c->v.rs);
708        if (nframe)
709          {
710           if (!last)
711              res=nframe;
712           else
713              last->next=nframe;
714           last=nframe;
715          }
716       }
717     c=c->next;
718    }
719  mi_free_results(r);
720  return res;
721 }
722
723 mi_frames *mi_res_frames_list(mi_h *h)
724 {
725  mi_output *r, *res;
726  mi_frames *ret=NULL, *nframe, *last=NULL;
727  mi_results *c;
728
729  r=mi_get_response_blk(h);
730  res=mi_get_rrecord(r);
731  if (res && res->tclass==MI_CL_DONE)
732    {
733     c=res->c;
734     while (c)
735       {
736        if (strcmp(c->var,"frame")==0 && c->type==t_tuple)
737          {
738           nframe=mi_parse_frame(c->v.rs);
739           if (nframe)
740             {
741              if (!last)
742                 ret=nframe;
743              else
744                 last->next=nframe;
745              last=nframe;
746             }
747          }
748        c=c->next;
749       }
750    }
751  mi_free_output(r);
752  return ret;
753 }
754
755 int mi_get_thread_ids(mi_output *res, int **list)
756 {
757  mi_results *vids, *lids;
758  int ids=-1, i;
759
760  *list=NULL;
761  vids=mi_get_var(res,"number-of-threads");
762  lids=mi_get_var(res,"thread-ids");
763  if (vids && vids->type==t_const &&
764      lids && lids->type==t_tuple)
765    {
766     ids=atoi(vids->v.cstr);
767     if (ids)
768       {
769        int *lst;
770        lst=(int *)mi_calloc(ids,sizeof(int));
771        if (lst)
772          {
773           lids=lids->v.rs;
774           i=0;
775           while (lids)
776             {
777              if (strcmp(lids->var,"thread-id")==0 && lids->type==t_const)
778                 lst[i++]=atoi(lids->v.cstr);
779              lids=lids->next;
780             }
781           *list=lst;
782          }
783        else
784           ids=-1;
785       }
786    }
787  return ids;
788 }
789
790 int mi_res_thread_ids(mi_h *h, int **list)
791 {
792  mi_output *r, *res;
793  int ids=-1;
794
795  r=mi_get_response_blk(h);
796  res=mi_get_rrecord(r);
797  if (res && res->tclass==MI_CL_DONE)
798     ids=mi_get_thread_ids(res,list);
799  mi_free_output(r);
800  return ids;
801 }
802
803 enum mi_gvar_lang mi_lang_str_to_enum(const char *lang)
804 {
805  enum mi_gvar_lang lg=lg_unknown;
806
807  if (strcmp(lang,"C")==0)
808     lg=lg_c;
809  else if (strcmp(lang,"C++")==0)
810     lg=lg_cpp;
811  else if (strcmp(lang,"Java")==0)
812     lg=lg_java;
813
814  return lg;
815 }
816
817 const char *mi_lang_enum_to_str(enum mi_gvar_lang lang)
818 {
819  const char *lg;
820
821  switch (lang)
822    {
823     case lg_c:
824          lg="C";
825          break;
826     case lg_cpp:
827          lg="C++";
828          break;
829     case lg_java:
830          lg="Java";
831          break;
832     /*case lg_unknown:*/
833     default:
834          lg="unknown";
835          break;
836    }
837  return lg;
838 }
839
840 enum mi_gvar_fmt mi_format_str_to_enum(const char *format)
841 {
842  enum mi_gvar_fmt fmt=fm_natural;
843
844  if (strcmp(format,"binary")==0)
845     fmt=fm_binary;
846  else if (strcmp(format,"decimal")==0)
847     fmt=fm_decimal;
848  else if (strcmp(format,"hexadecimal")==0)
849     fmt=fm_hexadecimal;
850  else if (strcmp(format,"octal")==0)
851     fmt=fm_octal;
852
853  return fmt;
854 }
855
856 const char *mi_format_enum_to_str(enum mi_gvar_fmt format)
857 {
858  const char *fmt;
859
860  switch (format)
861    {
862     case fm_natural:
863          fmt="natural";
864          break;
865     case fm_binary:
866          fmt="binary";
867          break;
868     case fm_decimal:
869          fmt="decimal";
870          break;
871     case fm_hexadecimal:
872          fmt="hexadecimal";
873          break;
874     case fm_octal:
875          fmt="octal";
876          break;
877     case fm_raw:
878          fmt="raw";
879          break;
880     default:
881          fmt="unknown";
882    }
883  return fmt;
884 }
885
886 char mi_format_enum_to_char(enum mi_gvar_fmt format)
887 {
888  char fmt;
889
890  switch (format)
891    {
892     case fm_natural:
893          fmt='N';
894          break;
895     case fm_binary:
896          fmt='t';
897          break;
898     case fm_decimal:
899          fmt='d';
900          break;
901     case fm_hexadecimal:
902          fmt='x';
903          break;
904     case fm_octal:
905          fmt='o';
906          break;
907     case fm_raw:
908          fmt='r';
909          break;
910     default:
911          fmt=' ';
912    }
913  return fmt;
914 }
915
916 mi_gvar *mi_get_gvar(mi_output *o, mi_gvar *cur, const char *expression)
917 {
918  mi_results *r;
919  mi_gvar *res=cur ? cur : mi_alloc_gvar();
920  int l;
921
922  if (!res)
923     return res;
924  r=o->c;
925  if (expression)
926     res->exp=strdup(expression);
927  while (r)
928    {
929     if (r->type==t_const)
930       {
931        if (strcmp(r->var,"name")==0)
932          {
933           free(res->name);
934           res->name=r->v.cstr;
935           r->v.cstr=NULL;
936          }
937        else if (strcmp(r->var,"numchild")==0)
938          {
939           res->numchild=atoi(r->v.cstr);
940          }
941        else if (strcmp(r->var,"type")==0)
942          {
943           free(res->type);
944           res->type=r->v.cstr;
945           r->v.cstr=NULL;
946           l=strlen(res->type);
947           if (l && res->type[l-1]=='*')
948              res->ispointer=1;
949          }
950        else if (strcmp(r->var,"lang")==0)
951          {
952           res->lang=mi_lang_str_to_enum(r->v.cstr);
953          }
954        else if (strcmp(r->var,"exp")==0)
955          {
956           free(res->exp);
957           res->exp=r->v.cstr;
958           r->v.cstr=NULL;
959          }
960        else if (strcmp(r->var,"format")==0)
961          {
962           res->format=mi_format_str_to_enum(r->v.cstr);
963          }
964        else if (strcmp(r->var,"attr")==0)
965          { /* Note: gdb 6.1.1 have only this: */
966           if (strcmp(r->v.cstr,"editable")==0)
967              res->attr=MI_ATTR_EDITABLE;
968           else /* noneditable */
969              res->attr=MI_ATTR_NONEDITABLE;
970          }
971       }
972     r=r->next;
973    }
974  return res;
975 }
976
977 mi_gvar *mi_res_gvar(mi_h *h, mi_gvar *cur, const char *expression)
978 {
979  mi_output *r, *res;
980  mi_gvar *gvar=NULL;
981
982  r=mi_get_response_blk(h);
983  res=mi_get_rrecord(r);
984  if (res && res->tclass==MI_CL_DONE)
985     gvar=mi_get_gvar(res,cur,expression);
986  mi_free_output(r);
987  return gvar;
988 }
989
990 mi_gvar_chg *mi_get_gvar_chg(mi_results *r)
991 {
992  mi_gvar_chg *n;
993
994  if (r->type!=t_const)
995     return NULL;
996  n=mi_alloc_gvar_chg();
997  if (n)
998    {
999     while (r)
1000       {
1001        if (r->type==t_const)
1002          {
1003           if (strcmp(r->var,"name")==0)
1004             {
1005              n->name=r->v.cstr;
1006              r->v.cstr=NULL;
1007             }
1008           else if (strcmp(r->var,"in_scope")==0)
1009             {
1010              n->in_scope=strcmp(r->v.cstr,"true")==0;
1011             }
1012           else if (strcmp(r->var,"new_type")==0)
1013             {
1014              n->new_type=r->v.cstr;
1015              r->v.cstr=NULL;
1016             }
1017           else if (strcmp(r->var,"new_num_children")==0)
1018             {
1019              n->new_num_children=atoi(r->v.cstr);
1020             }
1021           // type_changed="false" is the default
1022          }
1023        r=r->next;
1024       }
1025    }
1026  return n;
1027 }
1028
1029 int mi_res_changelist(mi_h *h, mi_gvar_chg **changed)
1030 {
1031  mi_gvar_chg *last, *n;
1032  mi_results *res=mi_res_done_var(h,"changelist"), *r;
1033  int count=0;
1034
1035  *changed=NULL;
1036  if (!res)
1037     return 0;
1038  last=NULL;
1039  count=1;
1040  n=NULL;
1041  r=res->v.rs;
1042
1043  if (res->type==t_list)
1044    {// MI v2 a list of tuples
1045     while (r)
1046       {
1047        if (r->type==t_tuple)
1048          {
1049           n=mi_get_gvar_chg(r->v.rs);
1050           if (n)
1051             {
1052              if (last)
1053                 last->next=n;
1054              else
1055                 *changed=n;
1056              last=n;
1057              count++;
1058             }
1059          }
1060        r=r->next;
1061       }
1062    }
1063  else if (res->type==t_tuple)
1064    {// MI v1 a tuple with all together *8-P
1065     while (r)
1066       {
1067        if (r->type==t_const) /* Just in case. */
1068          {/* Get one var. */
1069           if (strcmp(r->var,"name")==0)
1070             {
1071              if (n)
1072                {/* Add to the list*/
1073                 if (last)
1074                    last->next=n;
1075                 else
1076                    *changed=n;
1077                 last=n;
1078                 count++;
1079                }
1080              n=mi_alloc_gvar_chg();
1081              if (!n)
1082                {
1083                 mi_free_gvar_chg(*changed);
1084                 return 0;
1085                }
1086              n->name=r->v.cstr;
1087              r->v.cstr=NULL;
1088             }
1089           else if (strcmp(r->var,"in_scope")==0)
1090             {
1091              n->in_scope=strcmp(r->v.cstr,"true")==0;
1092             }
1093           else if (strcmp(r->var,"new_type")==0)
1094             {
1095              n->new_type=r->v.cstr;
1096              r->v.cstr=NULL;
1097             }
1098           else if (strcmp(r->var,"new_num_children")==0)
1099             {
1100              n->new_num_children=atoi(r->v.cstr);
1101             }
1102           // type_changed="false" is the default
1103          }
1104        r=r->next;
1105       }
1106     if (n)
1107       {/* Add to the list*/
1108        if (last)
1109           last->next=n;
1110        else
1111           *changed=n;
1112        last=n;
1113        count++;
1114       }
1115    }
1116  mi_free_results(res);
1117
1118  return count;
1119 }
1120
1121 int mi_get_children(mi_results *ch, mi_gvar *v)
1122 {
1123  mi_gvar *cur=NULL, *aux;
1124  int i=0, count=v->numchild, l;
1125
1126  while (ch)
1127    {
1128     if (strcmp(ch->var,"child")==0 && ch->type==t_tuple && i<count)
1129       {
1130        mi_results *r=ch->v.rs;
1131        aux=mi_alloc_gvar();
1132        if (!aux)
1133           return 0;
1134        if (!v->child)
1135           v->child=aux;
1136        else
1137           cur->next=aux;
1138        cur=aux;
1139        cur->parent=v;
1140        cur->depth=v->depth+1;
1141
1142        while (r)
1143          {
1144           if (r->type==t_const)
1145             {
1146              if (strcmp(r->var,"name")==0)
1147                {
1148                 cur->name=r->v.cstr;
1149                 r->v.cstr=NULL;
1150                }
1151              else if (strcmp(r->var,"exp")==0)
1152                {
1153                 cur->exp=r->v.cstr;
1154                 r->v.cstr=NULL;
1155                }
1156              else if (strcmp(r->var,"type")==0)
1157                {
1158                 cur->type=r->v.cstr;
1159                 r->v.cstr=NULL;
1160                 l=strlen(cur->type);
1161                 if (l && cur->type[l-1]=='*')
1162                    cur->ispointer=1;
1163                }
1164              else if (strcmp(r->var,"value")==0)
1165                {
1166                 cur->value=r->v.cstr;
1167                 r->v.cstr=NULL;
1168                }                     
1169              else if (strcmp(r->var,"numchild")==0)
1170                {
1171                 cur->numchild=atoi(r->v.cstr);
1172                }
1173             }
1174           r=r->next;
1175          }
1176        i++;
1177       }
1178     ch=ch->next;
1179    }
1180  v->vischild=i;
1181  v->opened=1;
1182  return i==v->numchild;
1183 }
1184
1185 int mi_res_children(mi_h *h, mi_gvar *v)
1186 {
1187  mi_output *r, *res;
1188  int ok=0;
1189
1190  r=mi_get_response_blk(h);
1191  res=mi_get_rrecord(r);
1192  if (res && res->tclass==MI_CL_DONE)
1193    {
1194     mi_results *num=mi_get_var(res,"numchild");
1195     if (num && num->type==t_const)
1196       {
1197        v->numchild=atoi(num->v.cstr);
1198        if (v->child)
1199          {
1200           mi_free_gvar(v->child);
1201           v->child=NULL;
1202          }
1203        if (v->numchild)
1204          {
1205           mi_results *ch =mi_get_var(res,"children");
1206           if (ch && ch->type!=t_const) /* MI v1 tuple, MI v2 list */
1207              ok=mi_get_children(ch->v.rs,v);
1208          }
1209        else
1210           ok=1;
1211       }
1212    }
1213  mi_free_output(r);
1214  return ok;
1215 }
1216
1217 mi_bkpt *mi_get_bkpt(mi_results *p)
1218 {
1219  mi_bkpt *res;
1220  char *end;
1221
1222  res=mi_alloc_bkpt();
1223  if (!res)
1224     return NULL;
1225  while (p)
1226    {
1227     if (p->type==t_const && p->var)
1228       {
1229        if (strcmp(p->var,"number")==0)
1230           res->number=atoi(p->v.cstr);
1231        else if (strcmp(p->var,"type")==0)
1232          {
1233           if (strcmp(p->v.cstr,"breakpoint")==0)
1234              res->type=t_breakpoint;
1235           else
1236              res->type=t_unknown;
1237          }
1238        else if (strcmp(p->var,"disp")==0)
1239          {
1240           if (strcmp(p->v.cstr,"keep")==0)
1241              res->disp=d_keep;
1242           else if (strcmp(p->v.cstr,"del")==0)
1243              res->disp=d_del;
1244           else
1245              res->disp=d_unknown;
1246          }
1247        else if (strcmp(p->var,"enabled")==0)
1248           res->enabled=p->v.cstr[0]=='y';
1249        else if (strcmp(p->var,"addr")==0)
1250           res->addr=(void *)strtoul(p->v.cstr,&end,0);
1251        else if (strcmp(p->var,"func")==0)
1252          {
1253           res->func=p->v.cstr;
1254           p->v.cstr=NULL;
1255          }
1256        else if (strcmp(p->var,"file")==0)
1257          {
1258           res->file=p->v.cstr;
1259           p->v.cstr=NULL;
1260          }
1261        else if (strcmp(p->var,"line")==0)
1262           res->line=atoi(p->v.cstr);
1263        else if (strcmp(p->var,"times")==0)
1264           res->times=atoi(p->v.cstr);
1265        else if (strcmp(p->var,"ignore")==0)
1266           res->ignore=atoi(p->v.cstr);
1267        else if (strcmp(p->var,"cond")==0)
1268          {
1269           res->cond=p->v.cstr;
1270           p->v.cstr=NULL;
1271          }
1272       }
1273     p=p->next;
1274    }
1275  return res;
1276 }
1277
1278 mi_bkpt *mi_res_bkpt(mi_h *h)
1279 {
1280  mi_results *r=mi_res_done_var(h,"bkpt");
1281  mi_bkpt *b=NULL;
1282
1283  if (r && r->type==t_tuple)
1284     b=mi_get_bkpt(r->v.rs);
1285  mi_free_results(r);
1286  return b;
1287 }
1288
1289 mi_wp *mi_get_wp(mi_results *p, enum mi_wp_mode m)
1290 {
1291  mi_wp *res=mi_alloc_wp();
1292
1293  if (res)
1294    {
1295     res->mode=m;
1296     while (p)
1297       {
1298        if (p->type==t_const && p->var)
1299          {
1300           if (strcmp(p->var,"number")==0)
1301             {
1302              res->number=atoi(p->v.cstr);
1303              res->enabled=1;
1304             }
1305           else if (strcmp(p->var,"exp")==0)
1306             {
1307              res->exp=p->v.cstr;
1308              p->v.cstr=NULL;
1309             }
1310          }
1311        p=p->next;
1312       }
1313    }
1314  return res;
1315 }
1316
1317 mi_wp *mi_parse_wp_res(mi_output *r)
1318 {
1319  mi_results *p;
1320  enum mi_wp_mode m=wm_unknown;
1321
1322  /* The info is in a result wpt=... */
1323  p=r->c;
1324  while (p)
1325    {
1326     if (p->var)
1327       {
1328        if (strcmp(p->var,"wpt")==0)
1329           m=wm_write;
1330        else if (strcmp(p->var,"hw-rwpt")==0)
1331           m=wm_read;
1332        else if (strcmp(p->var,"hw-awpt")==0)
1333           m=wm_rw;
1334        if (m!=wm_unknown)
1335           break;
1336       }
1337     p=p->next;
1338    }
1339  if (!p || p->type!=t_tuple)
1340     return NULL;
1341  /* Scan the values inside it. */
1342  return mi_get_wp(p->v.rs,m);
1343 }
1344
1345 mi_wp *mi_res_wp(mi_h *h)
1346 {
1347  mi_output *r, *res;
1348  mi_wp *ret=NULL;
1349
1350  r=mi_get_response_blk(h);
1351  res=mi_get_rrecord(r);
1352
1353  if (res)
1354     ret=mi_parse_wp_res(res);
1355
1356  mi_free_output(r);
1357  return ret;
1358 }
1359
1360 char *mi_res_value(mi_h *h)
1361 {
1362  mi_results *r=mi_res_done_var(h,"value");
1363  char *s=NULL;
1364
1365  if (r && r->type==t_const)
1366    {
1367     s=r->v.cstr;
1368     r->v.rs=NULL;
1369    }
1370  mi_free_results(r);
1371  return s;
1372 }
1373
1374 mi_output *mi_get_stop_record(mi_output *r)
1375 {
1376  while (r)
1377    {
1378     if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
1379         r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
1380        return r;
1381     r=r->next;
1382    }
1383  return r;
1384 }
1385
1386 static
1387 char *reason_names[]=
1388 {
1389  "breakpoint-hit",
1390  "watchpoint-trigger",
1391  "read-watchpoint-trigger",
1392  "access-watchpoint-trigger",
1393  "watchpoint-scope",
1394  "function-finished",
1395  "location-reached",
1396  "end-stepping-range",
1397  "exited-signalled",
1398  "exited",
1399  "exited-normally",
1400  "signal-received"
1401 };
1402
1403 static
1404 enum mi_stop_reason reason_values[]=
1405 {
1406  sr_bkpt_hit,
1407  sr_wp_trigger, sr_read_wp_trigger, sr_access_wp_trigger, sr_wp_scope,
1408  sr_function_finished, sr_location_reached, sr_end_stepping_range,
1409  sr_exited_signalled, sr_exited, sr_exited_normally,
1410  sr_signal_received
1411 };
1412
1413 static
1414 char *reason_expl[]=
1415 {
1416  "Hit a breakpoint",
1417  "Write watchpoint",
1418  "Read watchpoint",
1419  "Access watchpoint",
1420  "Watchpoint out of scope",
1421  "Function finished",
1422  "Location reached",
1423  "End of stepping",
1424  "Exited signalled",
1425  "Exited with error",
1426  "Exited normally",
1427  "Signal received"
1428 };
1429
1430 enum mi_stop_reason mi_reason_str_to_enum(const char *s)
1431 {
1432  int i;
1433
1434  for (i=0; i<sizeof(reason_names)/sizeof(char *); i++)
1435      if (strcmp(reason_names[i],s)==0)
1436         return reason_values[i];
1437  return sr_unknown;
1438 }
1439
1440 const char *mi_reason_enum_to_str(enum mi_stop_reason r)
1441 {
1442  int i;
1443
1444  if (r==sr_unknown)
1445     return "Unknown (temp bkp?)";
1446  for (i=0; i<sizeof(reason_values)/sizeof(char *); i++)
1447      if (reason_values[i]==r)
1448         return reason_expl[i];
1449  return NULL;
1450 }
1451
1452 mi_stop *mi_get_stopped(mi_results *r)
1453 {
1454  mi_stop *res=mi_alloc_stop();
1455
1456  if (res)
1457    {
1458     while (r)
1459       {
1460        if (r->type==t_const)
1461          {
1462           if (strcmp(r->var,"reason")==0)
1463              res->reason=mi_reason_str_to_enum(r->v.cstr);
1464           else if (!res->have_thread_id && strcmp(r->var,"thread-id")==0)
1465             {
1466              res->have_thread_id=1;
1467              res->thread_id=atoi(r->v.cstr);
1468             }
1469           else if (!res->have_bkptno && strcmp(r->var,"bkptno")==0)
1470             {
1471              res->have_bkptno=1;
1472              res->bkptno=atoi(r->v.cstr);
1473             }
1474           else if (!res->have_bkptno && strcmp(r->var,"wpnum")==0)
1475             {
1476              res->have_wpno=1;
1477              res->wpno=atoi(r->v.cstr);
1478             }
1479           else if (strcmp(r->var,"gdb-result-var")==0)
1480             {
1481              res->gdb_result_var=r->v.cstr;
1482              r->v.cstr=NULL;
1483             }
1484           else if (strcmp(r->var,"return-value")==0)
1485             {
1486              res->return_value=r->v.cstr;
1487              r->v.cstr=NULL;
1488             }
1489           else if (strcmp(r->var,"signal-name")==0)
1490             {
1491              res->signal_name=r->v.cstr;
1492              r->v.cstr=NULL;
1493             }
1494           else if (strcmp(r->var,"signal-meaning")==0)
1495             {
1496              res->signal_meaning=r->v.cstr;
1497              r->v.cstr=NULL;
1498             }
1499           else if (!res->have_exit_code && strcmp(r->var,"exit-code")==0)
1500             {
1501              res->have_exit_code=1;
1502              res->exit_code=atoi(r->v.cstr);
1503             }
1504          }
1505        else // tuple or list
1506          {
1507           if (strcmp(r->var,"frame")==0)
1508              res->frame=mi_parse_frame(r->v.rs);
1509           else if (!res->wp && strcmp(r->var,"wpt")==0)
1510              res->wp=mi_get_wp(r->v.rs,wm_write);
1511           else if (!res->wp && strcmp(r->var,"hw-rwpt")==0)
1512              res->wp=mi_get_wp(r->v.rs,wm_read);
1513           else if (!res->wp && strcmp(r->var,"hw-awpt")==0)
1514              res->wp=mi_get_wp(r->v.rs,wm_rw);
1515           else if (!(res->wp_old || res->wp_val) && strcmp(r->var,"value")==0)
1516              {
1517               mi_results *p=r->v.rs;
1518               while (p)
1519                 {
1520                  if (strcmp(p->var,"value")==0 || strcmp(p->var,"new")==0)
1521                    {
1522                     res->wp_val=p->v.cstr;
1523                     p->v.cstr=NULL;
1524                    }
1525                  else if (strcmp(p->var,"old")==0)
1526                    {
1527                     res->wp_old=p->v.cstr;
1528                     p->v.cstr=NULL;
1529                    }
1530                  p=p->next;
1531                 }
1532              }
1533          }
1534        r=r->next;
1535       }
1536    }
1537  return res;
1538 }
1539
1540 mi_stop *mi_res_stop(mi_h *h)
1541 {
1542  mi_output *o=mi_retire_response(h);
1543  mi_stop *stop=NULL;
1544
1545  if (o)
1546    {
1547     mi_output *sr=mi_get_stop_record(o);
1548     if (sr)
1549        stop=mi_get_stopped(sr->c);
1550    }
1551  mi_free_output(o);
1552
1553  return stop;
1554 }
1555
1556 int mi_get_read_memory(mi_h *h, unsigned char *dest, unsigned ws, int *na,
1557                        unsigned long *addr)
1558 {
1559  char *end;
1560  mi_results *res=mi_res_done_var(h,"memory"), *r;
1561  int ok=0;
1562
1563  *na=0;
1564  r=res;
1565  if (r && r->type==t_list && ws==1)
1566    {
1567     r=r->v.rs;
1568     if (r->type!=t_tuple)
1569       {
1570        mi_free_results(res);
1571        return 0;
1572       }
1573     r=r->v.rs;
1574     while (r)
1575       {
1576        if (r->type==t_list && strcmp(r->var,"data")==0)
1577          {
1578           mi_results *data=r->v.rs;
1579           ok++;
1580           if (data && data->type==t_const &&
1581               strcmp(data->v.cstr,"N/A")==0)
1582              *na=1;
1583           else
1584              while (data)
1585                {
1586                 if (data->type==t_const)
1587                    *(dest++)=strtol(data->v.cstr,&end,0);
1588                 data=data->next;
1589                }
1590          }
1591        else if (r->type==t_const && strcmp(r->var,"addr")==0)
1592          {
1593           ok++;
1594           if (addr)
1595              *addr=strtoul(r->v.cstr,&end,0);
1596          }
1597        r=r->next;
1598       }
1599
1600    }
1601  mi_free_results(res);
1602  return ok==2;
1603 }
1604
1605 mi_asm_insn *mi_parse_insn(mi_results *c)
1606 {
1607  mi_asm_insn *res=NULL, *cur=NULL;
1608  mi_results *sub;
1609  char *end;
1610
1611  while (c)
1612    {
1613     if (c->type==t_tuple)
1614       {
1615        if (!res)
1616           res=cur=mi_alloc_asm_insn();
1617        else
1618          {
1619           cur->next=mi_alloc_asm_insn();
1620           cur=cur->next;
1621          }
1622        if (!cur)
1623          {
1624           mi_free_asm_insn(res);
1625           return NULL;
1626          }
1627        sub=c->v.rs;
1628        while (sub)
1629          {
1630           if (sub->type==t_const)
1631             {
1632              if (strcmp(sub->var,"address")==0)
1633                 cur->addr=(void *)strtoul(sub->v.cstr,&end,0);
1634              else if (strcmp(sub->var,"func-name")==0)
1635                {
1636                 cur->func=sub->v.cstr;
1637                 sub->v.cstr=NULL;
1638                }
1639              else if (strcmp(sub->var,"offset")==0)
1640                 cur->offset=atoi(sub->v.cstr);
1641              else if (strcmp(sub->var,"inst")==0)
1642                {
1643                 cur->inst=sub->v.cstr;
1644                 sub->v.cstr=NULL;
1645                }
1646             }
1647           sub=sub->next;
1648          }
1649       }
1650     c=c->next;
1651    }
1652  return res;
1653 }
1654
1655 mi_asm_insns *mi_parse_insns(mi_results *c)
1656 {
1657  mi_asm_insns *res=NULL, *cur=NULL;
1658  mi_results *sub;
1659
1660  while (c)
1661    {
1662     if (c->var)
1663       {
1664        if (strcmp(c->var,"src_and_asm_line")==0 && c->type==t_tuple)
1665          {
1666           if (!res)
1667              res=cur=mi_alloc_asm_insns();
1668           else
1669             {
1670              cur->next=mi_alloc_asm_insns();
1671              cur=cur->next;
1672             }
1673           if (!cur)
1674             {
1675              mi_free_asm_insns(res);
1676              return NULL;
1677             }
1678           sub=c->v.rs;
1679           while (sub)
1680             {
1681              if (sub->var)
1682                {
1683                 if (sub->type==t_const)
1684                   {
1685                    if (strcmp(sub->var,"line")==0)
1686                       cur->line=atoi(sub->v.cstr);
1687                    else if (strcmp(sub->var,"file")==0)
1688                      {
1689                       cur->file=sub->v.cstr;
1690                       sub->v.cstr=NULL;
1691                      }
1692                   }
1693                 else if (sub->type==t_list)
1694                   {
1695                    if (strcmp(sub->var,"line_asm_insn")==0)
1696                       cur->ins=mi_parse_insn(sub->v.rs);
1697                   }
1698                }
1699              sub=sub->next;
1700             }
1701          }
1702       }
1703     else
1704       {/* No source line, just instructions */
1705        res=mi_alloc_asm_insns();
1706        res->ins=mi_parse_insn(c);
1707        break;
1708       }
1709     c=c->next;
1710    }
1711  return res;
1712 }
1713
1714
1715 mi_asm_insns *mi_get_asm_insns(mi_h *h)
1716 {
1717  mi_results *r=mi_res_done_var(h,"asm_insns");
1718  mi_asm_insns *f=NULL;
1719
1720  if (r && r->type==t_list)
1721     f=mi_parse_insns(r->v.rs);
1722  mi_free_results(r);
1723  return f;
1724 }
1725
1726 mi_chg_reg *mi_parse_list_regs(mi_results *r, int *how_many)
1727 {
1728  mi_results *c=r;
1729  int cregs=0;
1730  mi_chg_reg *first=NULL, *cur=NULL;
1731
1732  /* Create the list. */
1733  while (c)
1734    {
1735     if (c->type==t_const && !c->var)
1736       {
1737        if (first)
1738           cur=cur->next=mi_alloc_chg_reg();
1739        else
1740           first=cur=mi_alloc_chg_reg();
1741        cur->name=c->v.cstr;
1742        cur->reg=cregs++;
1743        c->v.cstr=NULL;
1744       }
1745     c=c->next;
1746    }
1747  if (how_many)
1748     *how_many=cregs;
1749
1750  return first;
1751 }
1752
1753 mi_chg_reg *mi_get_list_registers(mi_h *h, int *how_many)
1754 {
1755  mi_results *r=mi_res_done_var(h,"register-names");
1756  mi_chg_reg *l=NULL;
1757
1758  if (r && r->type==t_list)
1759     l=mi_parse_list_regs(r->v.rs,how_many);
1760  mi_free_results(r);
1761  return l;
1762 }
1763
1764 mi_chg_reg *mi_parse_list_changed_regs(mi_results *r)
1765 {
1766  mi_results *c=r;
1767  mi_chg_reg *first=NULL, *cur=NULL;
1768
1769  /* Create the list. */
1770  while (c)
1771    {
1772     if (c->type==t_const && !c->var)
1773       {
1774        if (first)
1775           cur=cur->next=mi_alloc_chg_reg();
1776        else
1777           first=cur=mi_alloc_chg_reg();
1778        cur->reg=atoi(c->v.cstr);
1779       }
1780     c=c->next;
1781    }
1782
1783  return first;
1784 }
1785
1786 mi_chg_reg *mi_get_list_changed_regs(mi_h *h)
1787 {
1788  mi_results *r=mi_res_done_var(h,"changed-registers");
1789  mi_chg_reg *changed=NULL;
1790
1791  if (r && r->type==t_list)
1792     changed=mi_parse_list_changed_regs(r->v.rs);
1793  mi_free_results(r);
1794  return changed;
1795 }
1796
1797 int mi_parse_reg_values(mi_results *r, mi_chg_reg *l)
1798 {
1799  mi_results *c;
1800
1801  while (r && l)
1802    {
1803     if (r->type==t_tuple && !r->var)
1804       {
1805        c=r->v.rs;
1806        while (c)
1807          {
1808           if (c->type==t_const && c->var)
1809             {
1810              if (strcmp(c->var,"number")==0)
1811                {
1812                 if (atoi(c->v.cstr)!=l->reg)
1813                   {
1814                    mi_error=MI_PARSER;
1815                    return 0;
1816                   }
1817                }
1818              else if (strcmp(c->var,"value")==0)
1819                {
1820                 l->val=c->v.cstr;
1821                 c->v.cstr=NULL;
1822                }
1823             }
1824           c=c->next;
1825          }
1826       }
1827     r=r->next;
1828     l=l->next;
1829    }
1830
1831  return !l && !r;
1832 }
1833
1834 int mi_get_reg_values(mi_h *h, mi_chg_reg *l)
1835 {
1836  mi_results *r=mi_res_done_var(h,"register-values");
1837  int ok=0;
1838
1839  if (r && r->type==t_list)
1840     ok=mi_parse_reg_values(r->v.rs,l);
1841  mi_free_results(r);
1842  return ok;
1843 }
1844
1845 int mi_parse_list_regs_l(mi_results *r, mi_chg_reg *l)
1846 {
1847  while (r && l)
1848    {
1849     if (r->type==t_const && !r->var)
1850       {
1851        free(l->name);
1852        l->name=r->v.cstr;
1853        r->v.cstr=NULL;
1854        l=l->next;
1855       }
1856     r=r->next;
1857    }
1858
1859  return !l && !r;
1860 }
1861
1862 int mi_get_list_registers_l(mi_h *h, mi_chg_reg *l)
1863 {
1864  mi_results *r=mi_res_done_var(h,"register-names");
1865  int ok=0;
1866
1867  if (r && r->type==t_list)
1868     ok=mi_parse_list_regs_l(r->v.rs,l);
1869  mi_free_results(r);
1870  return ok;
1871 }
1872
1873 mi_chg_reg *mi_parse_reg_values_l(mi_results *r, int *how_many)
1874 {
1875  mi_results *c;
1876  mi_chg_reg *first=NULL, *cur=NULL;
1877  *how_many=0;
1878
1879  while (r)
1880    {
1881     if (r->type==t_tuple && !r->var)
1882       {
1883        c=r->v.rs;
1884        if (first)
1885           cur=cur->next=mi_alloc_chg_reg();
1886        else
1887           first=cur=mi_alloc_chg_reg();
1888        while (c)
1889          {
1890           if (c->type==t_const && c->var)
1891             {
1892              if (strcmp(c->var,"number")==0)
1893                {
1894                 cur->reg=atoi(c->v.cstr);
1895                 (*how_many)++;
1896                }
1897              else if (strcmp(c->var,"value")==0)
1898                {
1899                 cur->val=c->v.cstr;
1900                 c->v.cstr=NULL;
1901                }
1902             }
1903           c=c->next;
1904          }
1905       }
1906     r=r->next;
1907    }
1908
1909  return first;
1910 }
1911
1912 mi_chg_reg *mi_get_reg_values_l(mi_h *h, int *how_many)
1913 {
1914  mi_results *r=mi_res_done_var(h,"register-values");
1915  mi_chg_reg *rgs=NULL;
1916
1917  if (r && r->type==t_list)
1918     rgs=mi_parse_reg_values_l(r->v.rs,how_many);
1919  mi_free_results(r);
1920  return rgs;
1921 }
1922
1923