File: format.c

package info (click to toggle)
grass 6.4.4-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 104,028 kB
  • ctags: 40,409
  • sloc: ansic: 419,980; python: 63,559; tcl: 46,692; cpp: 29,791; sh: 18,564; makefile: 7,000; xml: 3,505; yacc: 561; perl: 559; lex: 480; sed: 70; objc: 7
file content (213 lines) | stat: -rw-r--r-- 6,357 bytes parent folder | download | duplicates (2)
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
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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

/**
 * \file format.c
 *
 * \brief Segment formatting routines.
 *
 * This program is free software under the GNU General Public License
 * (>=v2). Read the file COPYING that comes with GRASS for details.
 *
 * \author GRASS GIS Development Team
 *
 * \date 2005-2006
 */

#include <grass/config.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <limits.h>
#include <grass/segment.h>


static int _segment_format(int, int, int, int, int, int, int);
static int write_int(int, int);
static int zero_fill(int, off_t);

/* fd must be open for write */


/**
 * \fn int segment_format (int fd, int nrows, int ncols, int srows, int scols, int len)
 *
 * \brief Format a segment file.
 *
 * The segmentation routines require a disk file to be used for paging 
 * segments in and out of memory. This routine formats the file open for 
 * write on file descriptor <b>fd</b> for use as a segment file.
 *
 * A segment file must be formatted before it can be processed by other 
 * segment routines. The configuration parameters <b>nrows</b>, 
 * <b>ncols</b>, <b>srows</b>, <b>scols</b>, and <b>len</b> are written 
 * to the beginning of the segment file which is then filled with zeros.
 *
 * The corresponding nonsegmented data matrix, which is to be 
 * transferred to the segment file, is <b>nrows</b> by <b>ncols</b>. The 
 * segment file is to be formed of segments which are <b>srows</b> by 
 * <b>scols</b>. The data items have length <b>len</b> bytes. For 
 * example, if the <em>data type is int</em>, <em>len is sizeof(int)</em>.
 *
 * \param[in] fd file descriptor
 * \param[in] nrows number of non-segmented rows
 * \param[in] ncols number of non-segmented columns
 * \param[in] srows segment rows
 * \param[in] scols segment columns
 * \param[in] len length of data type
 * \return 1 of successful
 * \return -1 if unable to seek or write <b>fd</b>
 * \return -3 if illegal parameters are passed
 */

int segment_format(int fd, int nrows, int ncols, int srows, int scols,
		   int len)
{
    return _segment_format(fd, nrows, ncols, srows, scols, len, 1);
}

/**
 * \fn int segment_format_nofill (int fd, int nrows, int ncols, int srows, int scols, int len)
 *
 * \brief Format a segment file.
 *
 * The segmentation routines require a disk file to be used for paging 
 * segments in and out of memory. This routine formats the file open for 
 * write on file descriptor <b>fd</b> for use as a segment file.
 *
 * A segment file must be formatted before it can be processed by other 
 * segment routines. The configuration parameters <b>nrows</b>, 
 * <b>ncols</b>, <b>srows</b>, <b>scols</b>, and <b>len</b> are written 
 * to the beginning of the segment file which is then filled with zeros.
 *
 * The corresponding nonsegmented data matrix, which is to be 
 * transferred to the segment file, is <b>nrows</b> by <b>ncols</b>. The 
 * segment file is to be formed of segments which are <b>srows</b> by 
 * <b>scols</b>. The data items have length <b>len</b> bytes. For 
 * example, if the <em>data type is int</em>, <em>len is sizeof(int)</em>.
 *
 * <b>Note:</b> This version of the function does <b>not</b> fill in the 
 * initialized data structures with zeros.
 *
 * \param[in] fd file descriptor
 * \param[in] nrows number of non-segmented rows
 * \param[in] ncols number of non-segmented columns
 * \param[in] srows segment rows
 * \param[in] scols segment columns
 * \param[in] len length of data type
 * \return 1 of successful
 * \return -1 if unable to seek or write <b>fd</b>
 * \return -3 if illegal parameters are passed
 */

int segment_format_nofill(int fd, int nrows, int ncols, int srows, int scols,
			  int len)
{
    return _segment_format(fd, nrows, ncols, srows, scols, len, 0);
}


static int _segment_format(int fd,
			   int nrows, int ncols,
			   int srows, int scols, int len, int fill)
{
    off_t nbytes;
    int spr, size;

    if (nrows <= 0 || ncols <= 0 || len <= 0 || srows <= 0 || scols <= 0) {
	G_warning("segment_format(fd,%d,%d,%d,%d,%d): illegal value(s)",
		  nrows, ncols, srows, scols, len);
	return -3;
    }

    if (lseek(fd, 0L, SEEK_SET) == (off_t) -1) {
	G_warning("segment_format(): Unable to seek (%s)", strerror(errno));
	return -1;
    }

    if (!write_int(fd, nrows) || !write_int(fd, ncols)
	|| !write_int(fd, srows) || !write_int(fd, scols)
	|| !write_int(fd, len))
	return -1;

    if (!fill)
	return 1;

    spr = ncols / scols;
    if (ncols % scols)
	spr++;

    size = srows * scols * len;

    /* calculate total number of segments */
    nbytes = spr * ((nrows + srows - 1) / srows);
    nbytes *= size;

    /* fill segment file with zeros */
    /* NOTE: this could be done faster using lseek() by seeking
     * ahead nbytes and then writing a single byte of 0,
     * provided lseek() on all version of UNIX will create a file
     * with holes that read as zeros.
     */
    if (zero_fill(fd, nbytes) < 0)
	return -1;

    return 1;
}


static int write_int(int fd, int n)
{
    if (write(fd, &n, sizeof(int)) != sizeof(int)) {
	G_warning("segment_format(): Unable to write (%s)", strerror(errno));
	return 0;
    }

    return 1;
}


static int zero_fill(int fd, off_t nbytes)
{
#ifndef USE_LSEEK
    char buf[10240];
    register char *b;
    register int n;

    /* zero buf */
    n = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;
    b = buf;
    while (n-- > 0)
	*b++ = 0;

    while (nbytes > 0) {
	n = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;
	if (write(fd, buf, n) != n) {
	    G_warning("segment zero_fill(): Unable to write (%s)", strerror(errno));
	    return -1;
	}
	nbytes -= n;
    }
    return 1;
#else
    /* Using lseek (faster upon initialization).
       NOTE: This version doesn't allocate disk storage for the file; storage will
       be allocated dynamically as blocks are actually written. This could 
       result in zero_fill() succeeding but a subsequent call to write() failing
       with ENOSPC ("No space left on device").
     */

    static const char buf[10];

    G_debug(3, "Using new segmentation code...");
    if (lseek(fd, nbytes - 1, SEEK_CUR) < 0) {
	G_warning("segment zero_fill(): Unable to seek (%s)", strerror(errno));
	return -1;
    }
    if (write(fd, buf, 1) != 1) {
	G_warning("segment zero_fill(): Unable to write (%s)", strerror(errno));
	return -1;
    }

    return 1;
#endif
}