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