File: read-mem.c

package info (click to toggle)
liboop 1.0.1-2
  • links: PTS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 2,108 kB
  • sloc: sh: 11,098; ansic: 2,533; makefile: 133
file content (157 lines) | stat: -rw-r--r-- 3,699 bytes parent folder | download | duplicates (16)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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
/* read-mem.c, liboop, copyright 2000 Ian jackson
   
   This is free software; you can redistribute it and/or modify it under the
   terms of the GNU Lesser General Public License, version 2.1 or later.
   See the file COPYING for details. */

#include "oop.h"
#include "oop-read.h"

#include <assert.h>
#include <string.h>

#include <unistd.h>
#include <limits.h>

typedef struct {
  oop_readable ra;
  oop_source *oop;
  int processing;
  enum { state_cancelled, state_active, state_dying } state;
  const char *data;
  size_t remaining;
  oop_readable_call *call;
  void *opaque;
} ram_intern;

static void *process(oop_source *oop, struct timeval when, void *ram_void);

static int set_time(ram_intern *ram) {
  int err;
  err=
    (ram->oop->on_time(ram->oop,OOP_TIME_NOW,process,ram), 0); /* fixme */
  if (err) return err;

  ram->processing= 1;
  return 0;
}

static void *process(oop_source *oop, struct timeval when, void *ram_void) {
  ram_intern *ram= ram_void;
  void *ret;
  int err;

  assert(oop == ram->oop);
  assert(ram->processing);

  ret= OOP_CONTINUE;

  while (ram->state == state_active && ret == OOP_CONTINUE) {
    ret= ram->call(oop,&ram->ra,ram->opaque);
  }

  switch (ram->state) {

  case state_active:
    err= set_time(ram);
    if (err)
      assert(!"must not lose flow of control");
         /* AAARGH! No way to avoid this I think.  Happens when:
	  *  - program calls on_read which works, setting immediate callback;
	  *  - process calls the application's function, which returns
	  *    OOP_HALT or some such, but without calling on_cancel;
	  *  Now we have to set another immediate callback.
	  *  If this fails and we were to ignore it then:
	  *  - program reenters event loop, expecting to deal with the rest
	  *    of the oop_readable_mem data.  But we've lost the flow
	  *    of control and the callback never happens, so
	  *    oop_sys_run or whatever would (lyingly) exit straight
	  *    away with OOP_CONTINUE.
	  *  Alternatively we could ignore the application's request
	  *  to abort the event loop, which seems just as bad.
	  */
    break;

  case state_cancelled:
    ram->processing= 0;
    break;

  case state_dying:
    oop_free(ram);
    break;
  }
  
  return ret;
}

static int on_read(oop_readable *ra, oop_readable_call *call, void *opaque) {
  ram_intern *ram= (void*)ra;

  assert(ram->state != state_dying);
  ram->state= state_active;
  ram->call= call;
  ram->opaque= opaque;

  if (ram->processing)
    return 0;

  return
    set_time(ram);
}

static void on_cancel(struct oop_readable *ra) {
  ram_intern *ram= (void*)ra;

  assert(ram->state != state_dying);
  ram->state= state_cancelled;
}

static ssize_t try_read(oop_readable *ra, void *buffer, size_t length) {
  ram_intern *ram= (void*)ra;

  if (length > SSIZE_MAX)
    length= SSIZE_MAX;

  if (length > ram->remaining)
    length= ram->remaining;

  memcpy(buffer,ram->data,length);
  ram->data += length;
  ram->remaining -= length;

  return length;
}

static void delete_kill(struct oop_readable *ra) {
  ram_intern *ram= (void*)ra;

  assert(ram->state != state_dying);
  ram->state= state_dying;
  if (!ram->processing)
    oop_free(ram);
}

static int delete_tidy(struct oop_readable *ra) {
  delete_kill(ra);
  return 0;
}

static const oop_readable functions= {
  on_read, on_cancel, try_read, delete_tidy, delete_kill
};

oop_readable *oop_readable_mem(oop_source *oop, const void *data, size_t length) {
  ram_intern *ram;

  ram= oop_malloc(sizeof(*ram));  if (!ram) return 0;

  ram->ra= functions;
  ram->oop= oop;
  ram->processing= 0;
  ram->state= state_cancelled;

  ram->data= data;
  ram->remaining= length;

  return (oop_readable*)ram;
}