1 // Copyright (C) 2005 and later by various people
2 // see monotone commit logs for details and authors
3 //
4 // This program is made available under the GNU GPL version 2.0 or
5 // greater. See the accompanying file COPYING for details.
6 //
7 // This program is distributed WITHOUT ANY WARRANTY; without even the
8 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9 // PURPOSE.
10 
11 
12 #include "base.hh"
13 #include "automate_reader.hh"
14 
15 #include <iostream>
16 
17 #include "sanity.hh"
18 
19 using std::istream;
20 using std::pair;
21 using std::streamsize;
22 using std::string;
23 using std::vector;
24 
get_string(string & out)25 bool automate_reader::get_string(string & out)
26 {
27   out.clear();
28   if (loc == none || loc == eof)
29     {
30       return false;
31     }
32   size_t size(0);
33   char c;
34   read(&c, 1);
35   if (c == 'e')
36     {
37       loc = none;
38       return false;
39     }
40   while(c <= '9' && c >= '0')
41     {
42       size = (size*10)+(c-'0');
43       read(&c, 1);
44     }
45   E(c == ':', origin::user,
46     F("bad input to automate stdio: expected ':' after string size"));
47   char *str = new char[size];
48   size_t got = 0;
49   while(got < size)
50     {
51       int n = read(str+got, size-got);
52       got += n;
53     }
54   out = string(str, size);
55   delete[] str;
56   L(FL("Got string '%s'") % out);
57   return true;
58 }
read(char * buf,size_t nbytes,bool eof_ok)59 streamsize automate_reader::read(char *buf, size_t nbytes, bool eof_ok)
60 {
61   streamsize rv;
62 
63   rv = in.rdbuf()->sgetn(buf, nbytes);
64 
65   E(eof_ok || rv > 0, origin::user,
66     F("bad input to automate stdio: unexpected EOF"));
67   return rv;
68 }
go_to_next_item()69 void automate_reader::go_to_next_item()
70 {
71   if (loc == eof)
72     return;
73   string starters("ol");
74   string whitespace(" \r\n\t");
75   string foo;
76   while (loc != none)
77     get_string(foo);
78   char c('e');
79   do
80     {
81       if (read(&c, 1, true) == 0)
82         {
83           loc = eof;
84           return;
85         }
86     }
87   while (whitespace.find(c) != string::npos);
88   switch (c)
89     {
90     case 'o': loc = opt; break;
91     case 'l': loc = cmd; break;
92     default:
93       E(false, origin::user,
94         F("bad input to automate stdio: unknown start token '%c'") % c);
95     }
96 }
automate_reader(istream & is)97 automate_reader::automate_reader(istream & is) : in(is), loc(none)
98 {}
get_command(vector<pair<string,string>> & params,vector<string> & cmdline)99 bool automate_reader::get_command(vector<pair<string, string> > & params,
100                                   vector<string> & cmdline)
101 {
102   params.clear();
103   cmdline.clear();
104   if (loc == none)
105     go_to_next_item();
106   if (loc == eof)
107     return false;
108   else if (loc == opt)
109     {
110       string key, val;
111       while(get_string(key) && get_string(val))
112         params.push_back(make_pair(key, val));
113       go_to_next_item();
114     }
115   E(loc == cmd, origin::user,
116     F("bad input to automate stdio: expected '%c' token") % cmd);
117   string item;
118   while (get_string(item))
119     {
120       cmdline.push_back(item);
121     }
122   E(cmdline.size() > 0, origin::user,
123     F("bad input to automate stdio: command name is missing"));
124   return true;
125 }
reset()126 void automate_reader::reset()
127 {
128   loc = none;
129 }
130 
131 
132 // Local Variables:
133 // mode: C++
134 // fill-column: 76
135 // c-file-style: "gnu"
136 // indent-tabs-mode: nil
137 // End:
138 // vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:
139