labcomm_fd_reader.c 3.45 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
  labcomm_fd_reader.c -- LabComm reader for Unix file descriptors.

  Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se>

  This file is part of LabComm.

  LabComm 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 3 of the License, or
  (at your option) any later version.

  LabComm 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, see <http://www.gnu.org/licenses/>.
*/

22
23
#include <errno.h>
#include <unistd.h>
24
25
#include <stdlib.h>
#include <string.h>
26
#include "labcomm_private.h"
27
#include "labcomm_fd_reader.h"
28
29
30

#define BUFFER_SIZE 2048

31
32
struct labcomm_fd_reader {
  struct labcomm_reader reader;
33
  struct labcomm_reader_action_context action_context;
34
35
36
37
  int fd;
  int close_fd_on_free;
};

38
39
static int fd_alloc(struct labcomm_reader *r,
		    struct labcomm_reader_action_context *action_context, 
40
		    char *version)
41
{
42
  int result = 0;
43
  
44
45
  r->count = 0;
  r->pos = 0;
46
  r->data = labcomm_memory_alloc(r->memory, 0, BUFFER_SIZE);
47
  if (! r->data) {
48
49
    r->data_size = 0;
    result = -ENOMEM;
50
  } else {
51

52
    r->data_size = BUFFER_SIZE;
53
54
55
56
57
58
59
60
61
62
    result = r->data_size;
    if (version && version[0]) {
      char *tmp;
      
      tmp = labcomm_read_string(r);
      if (strcmp(tmp, version) != 0) {
	result = -EINVAL;
      } else {
	result = r->data_size;
      }
63
      labcomm_memory_free(r->memory, 1, tmp);
64
65
    }
  }
66
67
68
  return result;
}

69
70
static int fd_free(struct labcomm_reader *r, 
		   struct labcomm_reader_action_context *action_context)
71
{
72
73
  struct labcomm_fd_reader *fd_reader = action_context->context;
  struct labcomm_memory *memory = r->memory;
74

75
  labcomm_memory_free(memory, 0, r->data);
76
77
78
79
  r->data = 0;
  r->data_size = 0;
  r->count = 0;
  r->pos = 0;
80

81
82
  if (fd_reader->close_fd_on_free) {
    close(fd_reader->fd);
83
  }
84
  labcomm_memory_free(memory, 0, fd_reader);
85

86
87
88
  return 0;
}

89
90
static int fd_fill(struct labcomm_reader *r, 
		   struct labcomm_reader_action_context *action_context)
91
{
92
  int result = 0;
93
  struct labcomm_fd_reader *fd_reader = action_context->context;
94
95
96
97
98
99
100

  if (r->pos < r->count) {
    result = r->count - r->pos;
  } else {
    int err;
    
    r->pos = 0;
101
    err = read(fd_reader->fd, (char *)r->data, r->data_size);
102
    if (err <= 0) {
103
      r->count = 0;
Anders Blomdell's avatar
Anders Blomdell committed
104
      r->error = -EPIPE;
105
106
107
108
      result = -EPIPE;
    } else {
      r->count = err;
      result = r->count - r->pos;
109
    }
110
111
112
113
  }
  return result;
}

114
static const struct labcomm_reader_action action = {
115
116
  .alloc = fd_alloc,
  .free = fd_free,
117
  .start = NULL,
118
  .fill = fd_fill,
119
120
  .end = NULL,
  .ioctl = NULL
121
};
122

123
124
struct labcomm_reader *labcomm_fd_reader_new(struct labcomm_memory *memory,
					     int fd, int close_fd_on_free)
125
126
127
{
  struct labcomm_fd_reader *result;

128
  result = labcomm_memory_alloc(memory, 0, sizeof(*result));
129
130
131
  if (result == NULL) {
    return NULL;
  } else {
132
133
134
    result->action_context.next = NULL;
    result->action_context.action = &action;
    result->action_context.context = result;
135
136
    result->reader.action_context = &result->action_context;
    result->reader.memory = memory;
137
138
139
140
141
    result->fd = fd;
    result->close_fd_on_free = close_fd_on_free;
    return &result->reader;
  }
}