sexp_commands.c 7.46 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
3
4
5
6
7
8
/* sexp_commands.c
 *
 * Reading and writing of s-expressions.
 *
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
9
 * Copyright (C) 1999 Balázs Scheidler, Niels Möller
Niels Möller's avatar
Niels Möller committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "sexp_commands.h"

#include "format.h"
Niels Möller's avatar
Niels Möller committed
29
#include "io.h"
30
#include "werror.h"
Niels Möller's avatar
Niels Möller committed
31
32
#include "xalloc.h"

33
34
#include <assert.h>

35
36
37
38
39
40
41
/* Forward declarations */
static struct catch_command catch_sexp_exceptions;
#define CATCH_SEXP (&catch_sexp_exceptions.super.super.super)

static struct read_sexp_command read_sexp;
#define READ_SEXP (&read_sexp.super.super)

42
43
44
45
#define GABA_DEFINE
#include "sexp_commands.h.x"
#undef GABA_DEFINE

Niels Möller's avatar
Niels Möller committed
46
47
48
49
#include "sexp_commands.c.x"

/* (write out sexp)
 *
50
 * Prints the sexp to tha abstract_write OUT. Returns the sexp. */
Niels Möller's avatar
Niels Möller committed
51
52
53

/* GABA:
   (class
54
     (name sexp_print_to)
Niels Möller's avatar
Niels Möller committed
55
56
57
58
59
60
61
     (super command)
     (vars
       (format . int)
       (dest object abstract_write)))
*/

static void
62
do_sexp_print(struct command *s,
Niels Möller's avatar
Niels Möller committed
63
64
65
66
	      struct lsh_object *a,
	      struct command_continuation *c,
	      struct exception_handler *e UNUSED)
{
67
  CAST(sexp_print_to, self, s);
Niels Möller's avatar
Niels Möller committed
68
69
70
71
72
73
74
75
76
77
  CAST_SUBTYPE(sexp, o, a);

  A_WRITE(self->dest, sexp_format(o, self->format, 0));
  if (self->format != SEXP_CANONICAL)
    A_WRITE(self->dest, ssh_format("\n"));

  COMMAND_RETURN(c, a);
}

struct command *
78
make_sexp_print_to(int format, struct abstract_write *dest)
Niels Möller's avatar
Niels Möller committed
79
{
80
81
  NEW(sexp_print_to, self);
  self->super.call = do_sexp_print;
Niels Möller's avatar
Niels Möller committed
82
83
84
85
86
87
  self->format = format;
  self->dest = dest;

  return &self->super;
}

88
struct lsh_object *
89
do_sexp_print_simple(struct command_simple *s,
90
91
		     struct lsh_object *a)
{
92
  CAST(sexp_print_command, self, s);
93
94
  CAST_SUBTYPE(abstract_write, dest, a);

95
  return &make_sexp_print_to(self->format, dest)->super;
96
97
98
}

struct command_simple *
99
make_sexp_print_command(int format)
100
{
101
  NEW(sexp_print_command, self);
102
  self->super.super.call = do_call_simple_command;
103
  self->super.call_simple = do_sexp_print_simple;
104
105
106
107
108
  self->format = format;

  return &self->super;
}

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* GABA:
   (class
     (name sexp_print_raw_hash_to)
     (super command)
     (vars
       (algorithm object hash_algorithm)
       (dest object abstract_write)))
*/

static void
do_print_raw_hash_to(struct command *s,
		     struct lsh_object *a,
		     struct command_continuation *c,
		     struct exception_handler *e UNUSED)
{
  CAST(sexp_print_raw_hash_to, self, s);
  CAST_SUBTYPE(sexp, o, a);

127
  struct lsh_string *canonical = sexp_format(o, SEXP_CANONICAL, 0);
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  struct hash_instance *hash = MAKE_HASH(self->algorithm);
  struct lsh_string *digest = lsh_string_alloc(hash->hash_size);

  HASH_UPDATE(hash, canonical->length, canonical->data);
  HASH_DIGEST(hash, digest->data);
  
  lsh_string_free(canonical);
  KILL(hash);

  A_WRITE(self->dest, ssh_format("%lxfS", digest));

  COMMAND_RETURN(c, a);
}

struct command *
make_sexp_print_raw_hash_to(struct hash_algorithm *algorithm,
			    struct abstract_write *dest)
{
  NEW(sexp_print_raw_hash_to, self);
  self->super.call = do_print_raw_hash_to;
  self->algorithm = algorithm;
  self->dest = dest;

  return &self->super;
}

static struct lsh_object *
collect_print_raw_hash_2(struct collect_info_2 *info,
			 struct lsh_object *a,
			 struct lsh_object *d)
{
  CAST_SUBTYPE(hash_algorithm, algorithm, a);
  CAST_SUBTYPE(abstract_write, dest, d);

  assert(!info->next);
  
  return &make_sexp_print_raw_hash_to(algorithm, dest)->super;
}

struct collect_info_2 collect_info_print_raw_2 =
STATIC_COLLECT_2_FINAL(collect_print_raw_hash_2);

struct collect_info_1 sexp_print_raw_hash =
STATIC_COLLECT_1(&collect_info_print_raw_2);

struct command *
make_sexp_print_raw_hash(struct hash_algorithm *algorithm)
{
  CAST_SUBTYPE(command, print,
	       make_collect_state_1(&sexp_print_raw_hash, &algorithm->super));
  
  return print;
}

#if 0 
static struct lsh_object *
do_print_raw_hash_simple(struct command_simple *s UNUSED,
			 struct lsh_object *a)
{
  CAST_SUBTYPE(abstract_write, dest, a);

  return &make_print_raw_hash_to(dest)->super;
}

struct command_simple sexp_print_raw_hash =
STATIC_COMMAND_SIMPLE(do_print_raw_hash_simple);
#endif

196
/* Make sure that the fd is closed properly. */
Niels Möller's avatar
Niels Möller committed
197
198
/* GABA:
   (class
199
200
     (name read_sexp_continuation)
     (super command_continuation)
Niels Möller's avatar
Niels Möller committed
201
     (vars
202
203
       (fd object lsh_fd)
       (up object command_continuation)))
Niels Möller's avatar
Niels Möller committed
204
205
*/

206
207
static void
do_read_sexp_continue(struct command_continuation *s,
Niels Möller's avatar
Niels Möller committed
208
209
		      struct lsh_object *a)
{
210
211
  CAST(read_sexp_continuation, self, s);
  close_fd_nicely(self->fd, 0);
Niels Möller's avatar
Niels Möller committed
212

213
214
  trace("do_read_sexp_continue\n");
  
215
  COMMAND_RETURN(self->up, a);
Niels Möller's avatar
Niels Möller committed
216
217
}

218
static struct command_continuation*
Niels Möller's avatar
Niels Möller committed
219
make_read_sexp_continuation(struct lsh_fd *fd,
220
			    struct command_continuation *up)
Niels Möller's avatar
Niels Möller committed
221
{
222
  NEW(read_sexp_continuation, self);
223
224

  trace("make_read_sexp_continuation\n");
Niels Möller's avatar
Niels Möller committed
225
  self->super.c = do_read_sexp_continue;
Niels Möller's avatar
Niels Möller committed
226
  self->fd = fd;
227
  self->up = up;
Niels Möller's avatar
Niels Möller committed
228
229
230
231
232
233

  return &self->super;
}

/* GABA:
   (class
234
235
     (name read_sexp_exception_handler)
     (super exception_handler)
Niels Möller's avatar
Niels Möller committed
236
     (vars
237
       (fd object lsh_fd)))
Niels Möller's avatar
Niels Möller committed
238
239
*/

240
241
242
243
244
245
246
247
248
249
250
251
static void
do_read_sexp_exception_handler(struct exception_handler *s,
			       const struct exception *x)
{
  CAST(read_sexp_exception_handler, self, s);
  if (x->type & EXC_SEXP)
    close_fd_nicely(self->fd, 0);

  EXCEPTION_RAISE(self->super.parent, x);
}

static struct exception_handler *
Niels Möller's avatar
Niels Möller committed
252
make_read_sexp_exception_handler(struct lsh_fd *fd,
253
254
				 struct exception_handler *e,
				 const char *context)
255
256
{
  NEW(read_sexp_exception_handler, self);
257
258
259

  trace("make_read_sexp_exception_handler\n");

260
261
  self->super.raise = do_read_sexp_exception_handler;
  self->super.parent = e;
262
263
  self->super.context = context;
  
Niels Möller's avatar
Niels Möller committed
264
  self->fd = fd;
265
266
267
268

  return &self->super;
}

Niels Möller's avatar
Niels Möller committed
269
270
#define SEXP_BUFFER_SIZE 1024

271
void
Niels Möller's avatar
Niels Möller committed
272
273
274
275
276
277
do_read_sexp(struct command *s,
	     struct lsh_object *a,
	     struct command_continuation *c,
	     struct exception_handler *e)
{
  CAST(read_sexp_command, self, s);
278
  CAST(lsh_fd, fd, a);
Niels Möller's avatar
Niels Möller committed
279

280
  trace("do_read_sexp\n");
281
    
282
283
  assert(fd);
  
284
285
286
  if (!self->goon)
    c = make_read_sexp_continuation(fd, c);
  
Niels Möller's avatar
Niels Möller committed
287
288
  io_read(fd,
	  make_buffered_read(SEXP_BUFFER_SIZE,
289
290
291
 	    make_read_sexp(self->format, self->goon, c,
	      make_read_sexp_exception_handler(fd, e,
					       HANDLER_CONTEXT))),
Niels Möller's avatar
Niels Möller committed
292
293
294
295
296
297
298
	  NULL);
}

struct command *
make_read_sexp_command(int format, int goon)
{
  NEW(read_sexp_command, self);
299
300
301

  trace("make_read_sexp_command\n");
  
Niels Möller's avatar
Niels Möller committed
302
303
304
305
306
307
  self->super.call = do_read_sexp;
  self->format = format;
  self->goon = goon;

  return &self->super;
}
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

static struct catch_command catch_sexp_exceptions
= STATIC_CATCH_COMMAND(EXC_ALL, EXC_SEXP_EOF, 1);

static struct read_sexp_command read_sexp
= STATIC_READ_SEXP(SEXP_ADVANCED, 1);

/* GABA:
   (expr
     (name for_sexp)
     (params
       (handler object command))
     (expr
       (lambda (proc)
         (catch_sexp handler
	             (lambda (file)
		       (proc (read_sexp file)))))))
*/

COMMAND_SIMPLE(for_sexp_command)
{
  CAST_SUBTYPE(command, handler, a);
  return for_sexp(handler);
}