|
|
1.1 root 1: #ifndef lint
2: static char rcs_id[] = "$Header: EDiskSrc.c,v 1.5 87/09/11 08:21:59 toddb Exp $";
3: #endif
4:
5: /*
6: * COPYRIGHT 1987
7: * DIGITAL EQUIPMENT CORPORATION
8: * MAYNARD, MASSACHUSETTS
9: * ALL RIGHTS RESERVED.
10: *
11: * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
12: * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
13: * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
14: * ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
15: *
16: * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
17: * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
18: * SET FORTH ABOVE.
19: *
20: *
21: * Permission to use, copy, modify, and distribute this software and its
22: * documentation for any purpose and without fee is hereby granted, provided
23: * that the above copyright notice appear in all copies and that both that
24: * copyright notice and this permission notice appear in supporting documentation,
25: * and that the name of Digital Equipment Corporation not be used in advertising
26: * or publicity pertaining to distribution of the software without specific,
27: * written prior permission.
28: */
29:
30: /* File: TEDiskSource.c - last edit by */
31: /* weissman: 25 Aug 86 */
32:
33: #include <sys/types.h>
34: #include <sys/stat.h>
35: #include <sys/file.h>
36: #include "xedit.h"
37: /* Private definitions. */
38:
39: #define BUFSIZE 512
40:
41: extern char *malloc();
42: extern char *realloc();
43: extern char *strcpy();
44:
45: typedef struct {
46: char *buf;
47: int length;
48: int maxlength;
49: long start;
50: } PieceRec, *PiecePtr;
51:
52: typedef struct {
53: int file;
54: char *name;
55: XtTextPosition length;
56: XtTextPosition origlength;
57: int numpieces;
58: PiecePtr piece;
59: short changed, everchanged;
60: short startsvalid;
61: short eversaved;
62: XtEditType editMode;
63: } EDiskRec, *EDiskPtr;
64:
65:
66: static CalculateStarts(data)
67: EDiskPtr data;
68: {
69: int i;
70: PiecePtr piece;
71: long start = 0;
72: for (i = 0, piece = data->piece; i < data->numpieces; i++, piece++) {
73: piece->start = start;
74: start += piece->length;
75: }
76: data->startsvalid = TRUE;
77: }
78:
79: static ReadPiece(data, i)
80: EDiskPtr data;
81: int i;
82: {
83: PiecePtr piece = data->piece + i;
84: piece->maxlength = piece->length;
85: piece->buf = malloc(piece->maxlength);
86: lseek(data->file, i * BUFSIZE, 0);
87: read(data->file, piece->buf, piece->length);
88: }
89:
90:
91:
92: static PiecePtr PieceFromPosition(data, position)
93: EDiskPtr data;
94: XtTextPosition position;
95: {
96: int i;
97: PiecePtr piece;
98: if (!data->everchanged) {
99: i = position / BUFSIZE;
100: if (i >= data->numpieces) i = data->numpieces - 1;
101: piece = data->piece + i;
102: } else {
103: if (!data->startsvalid)
104: CalculateStarts(data);
105: for (i = 0, piece = data->piece; i < data->numpieces - 1; i++, piece++)
106: if (position < piece->start + piece->length)
107: break;
108: }
109: if (!piece->buf) ReadPiece(data, i);
110: return piece;
111: }
112:
113: static XtTextPosition CoerceToLegalPosition(data, position)
114: EDiskPtr data;
115: XtTextPosition position;
116: {
117: return (position < 0) ? 0 :
118: ((position > data->length) ? data->length : position);
119: }
120:
121:
122: /* Semi-public definitions */
123:
124: static EDiskReadText(src, position, text, maxRead)
125: XtTextSource *src;
126: XtTextPosition position;
127: XtTextBlock *text;
128: int maxRead;
129: {
130: EDiskPtr data = (EDiskPtr) src->data;
131: PiecePtr piece;
132: int count;
133: text->firstPos = position;
134: if (position < data->length) {
135: piece = PieceFromPosition(data, position);
136: text->ptr = piece->buf + (position - piece->start);
137: count = piece->length - (position - piece->start);
138: text->length = (count < maxRead) ? count : maxRead;
139: }
140: else {
141: text->length = 0;
142: text->ptr = "";
143: }
144: return position + text->length;
145: }
146:
147:
148: static EDiskReplaceText(src, startPos, endPos, text, Delta)
149: XtTextSource *src;
150: XtTextPosition startPos, endPos;
151: XtTextBlock *text;
152: int *Delta;
153: {
154: EDiskPtr data = (EDiskPtr) src->data;
155: PiecePtr piece, piece2;
156: int oldlength = endPos - startPos;
157: int delta = text->length - oldlength;
158: int i;
159: switch (data->editMode) {
160: case XttextAppend:
161: if (startPos != endPos || endPos!= data->length)
162: return (POSITIONERROR);
163: break;
164: case XttextRead:
165: return (EDITERROR);
166: case XttextEdit:
167: break;
168: default:
169: return (EDITERROR);
170: }
171:
172: if (delta == 0 && oldlength == 0)
173: return 0;
174: data->length += delta;
175: piece = PieceFromPosition(data, startPos);
176: if (oldlength > 0) {
177: piece2 = PieceFromPosition(data, endPos - 1);
178: if (piece != piece2) {
179: oldlength = endPos - piece2->start;
180: piece2->length -= oldlength;
181: for (i = 0; i < piece2->length; i++)
182: piece2->buf[i] = piece2->buf[i + oldlength];
183: for (piece2--; piece2 > piece; piece2--)
184: piece2->length = 0;
185: oldlength = piece->length - (startPos - piece->start);
186: delta = text->length - oldlength;
187: }
188: }
189: data->changed = data->everchanged = TRUE;
190: data->startsvalid = FALSE;
191: piece->length += delta;
192: if (piece->length > piece->maxlength) {
193: do
194: piece->maxlength *= 2;
195: while (piece->length > piece->maxlength);
196: piece->buf = realloc(piece->buf, piece->maxlength);
197: }
198: if (delta < 0) /* insert shorter than delete, text getting
199: shorter */
200: for (i = startPos - piece->start; i < piece->length; i++)
201: piece->buf[i] = piece->buf[i - delta];
202: else
203: if (delta > 0) /* insert longer than delete, text getting
204: longer */
205: for (i = piece->length - delta;
206: i >= startPos - piece->start;
207: i--)
208: piece->buf[i + delta] = piece->buf[i];
209: if (text->length) /* do insert */
210: for (i = 0; i < text->length; ++i)
211: if ((piece->buf[startPos - piece->start + i] = text->ptr[i]) == CR)
212: piece->buf[startPos - piece->start + i] = LF;
213: *Delta = text->length - (endPos - startPos);
214: return EDITDONE;
215: }
216:
217:
218: static XtTextPosition EDiskGetLastPos(src)
219: XtTextSource *src;
220: {
221: return ((EDiskPtr) src->data)->length;
222: }
223:
224:
225: static EDiskSetLastPos(src)
226: XtTextSource *src;
227: {
228: }
229:
230: #define Look(index, c)\
231: { \
232: if ((dir == XtsdLeft && index <= 0) || \
233: (dir == XtsdRight && index >= data->length)) \
234: c = 0; \
235: else { \
236: if (index + doff < piece->start || \
237: index + doff >= piece->start + piece->length) \
238: piece = PieceFromPosition(data, index + doff); \
239: c = piece->buf[index + doff - piece->start]; \
240: } \
241: }
242:
243:
244:
245: static XtTextPosition EDiskScan(src, position, sType, dir, count, include)
246: XtTextSource *src;
247: XtTextPosition position;
248: ScanType sType;
249: ScanDirection dir;
250: int count, include;
251: {
252: EDiskPtr data = (EDiskPtr) src->data;
253: XtTextPosition index;
254: PiecePtr piece;
255: char c;
256: int ddir, doff, i, whiteSpace;
257: ddir = (dir == XtsdRight) ? 1 : -1;
258: doff = (dir == XtsdRight) ? 0 : -1;
259:
260: index = position;
261: piece = data->piece;
262: switch (sType) {
263: case XtstPositions:
264: if (!include && count > 0)
265: count--;
266: index = CoerceToLegalPosition(data, index + count * ddir);
267: break;
268: case XtstWhiteSpace: /* %%% This seems to ignore the fact that
269: whitespace can come in big chunks */
270: for (i = 0; i < count; i++) {
271: whiteSpace = -1;
272: while (index >= 0 && index <= data->length) {
273: Look(index, c);
274: if ((c == ' ') || (c == '\t') || (c == '\n')) {
275: if (whiteSpace < 0) whiteSpace = index;
276: } else if (whiteSpace >= 0)
277: break;
278: index += ddir;
279: }
280: }
281: if (!include) {
282: if (whiteSpace < 0 && dir == XtsdRight) whiteSpace = data->length;
283: index = whiteSpace;
284: }
285: index = CoerceToLegalPosition(data, index);
286: break;
287: case XtstEOL:
288: for (i = 0; i < count; i++) {
289: while (index >= 0 && index <= data->length) {
290: Look(index, c);
291: if (c == '\n')
292: break;
293: index += ddir;
294: }
295: if (i < count - 1)
296: index += ddir;
297: }
298: if (include)
299: index += ddir;
300: index = CoerceToLegalPosition(data, index);
301: break;
302: case XtstFile:
303: if (dir == XtsdLeft)
304: index = 0;
305: else
306: index = data->length;
307: break;
308: }
309: return index;
310: }
311:
312: static XtEditType TEDiskGetEditType(src)
313: XtTextSource *src;
314: {
315: EDiskPtr data = (EDiskPtr) src->data;
316: return(data->editMode);
317: }
318:
319:
320: /* Public definitions. */
321:
322: XtTextSource *TCreateEDiskSource(name, mode)
323: char *name;
324: XtEditType mode;
325: {
326: XtTextSource * src;
327: EDiskPtr data;
328: struct stat stat;
329: int i;
330: src = (XtTextSource *) malloc(sizeof(XtTextSource));
331: src->read = EDiskReadText;
332: src->replace = EDiskReplaceText;
333: src->getLastPos = EDiskGetLastPos;
334: src->setLastPos = EDiskSetLastPos;
335: src->editType = TEDiskGetEditType;
336: src->scan = EDiskScan;
337: data = (EDiskPtr) malloc(sizeof(EDiskRec));
338: src->data = (int *) data;
339: data->file = open(name, O_RDONLY | O_CREAT, 0666);
340: data->name = strcpy(malloc(strlen(name) + 1), name);
341: fstat(data->file, &stat);
342: data->length = data->origlength = stat.st_size;
343: data->numpieces = (data->length + BUFSIZE - 1) / BUFSIZE;
344: if (data->numpieces < 1)
345: data->numpieces = 1;
346: data->piece = (PiecePtr) malloc(data->numpieces * sizeof(PieceRec));
347: for (i = 0; i < data->numpieces; i++) {
348: data->piece[i].buf = 0;
349: data->piece[i].length = BUFSIZE;
350: data->piece[i].start = i * BUFSIZE;
351: }
352: data->piece[data->numpieces - 1].length -=
353: data->numpieces * BUFSIZE - data->length;
354: data->startsvalid = TRUE;
355: data->changed = data->everchanged = data->eversaved = FALSE;
356: if (data->length == 0) {
357: data->piece[0].buf = malloc(1);
358: data->piece[0].maxlength = 1;
359: }
360: data->editMode = mode;
361: return src;
362: }
363:
364:
365: TEDiskChanged(src)
366: XtTextSource *src;
367: {
368: return ((EDiskPtr) src->data)->changed;
369: }
370:
371: TEDiskSaveFile(src)
372: XtTextSource *src;
373: {
374: EDiskPtr data = (EDiskPtr) src->data;
375: PiecePtr piece;
376: int i, needlseek;
377: if (!data->changed)
378: return;
379: data->changed = FALSE;
380: if (!data->eversaved) {
381: data->eversaved = TRUE;
382: close(data->file);
383: data->file = open(data->name, O_RDWR, 0666);
384: }
385: if (!data->startsvalid)
386: CalculateStarts(data);
387: for (i = 0, piece = data->piece; i < data->numpieces; i++, piece++) {
388: if (!(piece->buf) && i * BUFSIZE != piece->start)
389: ReadPiece(data, i);
390: }
391: needlseek = TRUE;
392: for (i = 0, piece = data->piece; i < data->numpieces; i++, piece++) {
393: if (piece->buf) {
394: if (needlseek) {
395: lseek(data->file, piece->start, 0);
396: needlseek = FALSE;
397: }
398: write(data->file, piece->buf, piece->length);
399: }
400: else
401: needlseek = TRUE;
402: }
403: if (data->length < data->origlength)
404: ftruncate(data->file, data->length);
405: data->origlength = data->length;
406: }
407:
408: TEDiskSaveAsFile(src, filename)
409: XtTextSource *src;
410: char *filename;
411: {
412: EDiskPtr data = (EDiskPtr) src->data;
413: int i;
414: PiecePtr piece;
415: if (strcmp(filename, data->name) != 0) {
416: for (i = 0, piece = data->piece; i < data->numpieces; i++, piece++)
417: if (!(piece->buf))
418: ReadPiece(data, i);
419: data->eversaved = FALSE;
420: data->origlength = 0;
421: data->file = creat(filename, 0666);
422: data->eversaved = TRUE;
423: data->origlength = 0;
424: free(data->name);
425: data->name = strcpy(malloc(strlen(filename) + 1), filename);
426: data->changed = TRUE;
427: }
428: TEDiskSaveFile(src);
429: }
430:
431:
432: TDestroyEDiskSource(src)
433: XtTextSource *src;
434: {
435: EDiskPtr data = (EDiskPtr) src->data;
436: int i;
437: char *ptr;
438: close(data->file);
439: for (i=0 ; i<data->numpieces ; i++)
440: if (ptr = data->piece[i].buf) free(ptr);
441: free(data->piece);
442: free(data->name);
443: free(data);
444: free(src);
445: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.