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