• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

thoni56 / c-xrefactory / 1790

04 May 2026 07:10PM UTC coverage: 85.157% (-0.002%) from 85.159%
1790

push

travis-ci

thoni56
[tidy] Rename two mapping functions and some more tidying

16402 of 19261 relevant lines covered (85.16%)

15901657.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.43
src/editor.c
1
#include "editor.h"
2

3
#include <stdlib.h>
4
#include <memory.h>
5

6
#include "commons.h"
7
#include "editorbuffer.h"
8
#include "editorbuffertable.h"
9
#include "encoding.h"
10
#include "fileio.h"
11
#include "filetable.h"
12
#include "list.h"
13
#include "log.h"
14
#include "misc.h"
15
#include "proto.h"
16
#include "referenceableitemtable.h"
17
#include "referencerefresh.h"
18
#include "timestamp.h"
19
#include "undo.h"
20
#include "usage.h"
21

22

23
typedef struct editorMemoryBlock {
24
    struct editorMemoryBlock *next;
25
} EditorMemoryBlock;
26

27

28
#define MIN_EDITOR_MEMORY_BLOCK_SIZE_BITS 11 /* 11 bits will be 2^11 bytes in size */
29
#define MAX_EDITOR_MEMORY_BLOCK_SIZE_BITS 32 /* 32 bits will be 2^32 bytes in size */
30

31
// this has to cover at least alignment allocations
32
#define EDITOR_ALLOCATION_RESERVE 1024
33
#define EDITOR_FREE_PREFIX_SIZE 16
34

35
/* 32 entries, only 11-32 is used, pointers to allocated areas.
36
   I have no idea why this is so complicated, why not just use
37
   allocated memory, why keep it in this array? */
38
static EditorMemoryBlock *editorMemory[MAX_EDITOR_MEMORY_BLOCK_SIZE_BITS];
39

40

41
void editorInit(void) {
228✔
42
    initEditorBufferTable();
228✔
43
}
228✔
44

45
FileTimestamp editorFileModificationTime(char *path) {
1,029,071✔
46
    EditorBuffer *buffer;
1,029,071✔
47

48
    buffer = getEditorBufferForFile(path);
1,029,071✔
49
    if (buffer != NULL)
1,029,071✔
50
        return buffer->modificationTime;
1,021,116✔
51
    return fileModificationTime(path);
7,955✔
52
}
53

54
size_t editorFileSize(char *path) {
48✔
55
    EditorBuffer *buffer;
48✔
56

57
    buffer = getEditorBufferForFile(path);
48✔
58
    if (buffer != NULL)
48✔
59
        return buffer->size;
×
60
    return fileSize(path);
48✔
61
}
62

63
bool editorFileExists(char *path) {
1,042,653✔
64
    EditorBuffer *buffer;
1,042,653✔
65

66
    buffer = getEditorBufferForFile(path);
1,042,653✔
67
    if (buffer != NULL && buffer->preLoadedFromFile != NULL)
1,042,653✔
68
        return true;
69
    return fileExists(path);
1,042,296✔
70
}
71

72
static void editorError(int errCode, char *message) {
×
73
    errorMessage(errCode, message);
×
74
}
75

76
void freeTextSpace(char *space, int index) {
462,006✔
77
    EditorMemoryBlock *sp;
462,006✔
78
    sp = (EditorMemoryBlock *) space;
462,006✔
79
    sp->next = editorMemory[index];
462,006✔
80
    editorMemory[index] = sp;
462,006✔
81
}
462,006✔
82

83
void loadTextIntoEditorBuffer(EditorBuffer *buffer, FileTimestamp modificationTime, const char *text) {
4✔
84
    allocateNewEditorBufferTextSpace(buffer, strlen(text));
4✔
85
    strcpy(buffer->allocation.text, text);
4✔
86
}
4✔
87

88
void loadFileIntoEditorBuffer(EditorBuffer *buffer, FileTimestamp modificationTime, size_t fileSize) {
462,146✔
89
    allocateNewEditorBufferTextSpace(buffer, fileSize);
462,146✔
90

91
    char *text = buffer->allocation.text;
462,146✔
92
    assert(text != NULL);
93

462,146✔
94
    assert(buffer->preLoadedFromFile == NULL || buffer->preLoadedFromFile != buffer->fileName);
462,146✔
95
    int bufferSize = buffer->allocation.bufferSize;
96
    char *fileName = buffer->preLoadedFromFile? buffer->preLoadedFromFile: buffer->fileName;
462,146✔
97

98
    log_trace(":loading file %s==%s size %d", fileName, buffer->fileName, bufferSize);
462,146✔
99

462,146✔
100
    FILE *file = openFile(fileName, "r");
×
101
    if (file == NULL) {
102
        FATAL_ERROR(ERR_CANT_OPEN, fileName, EXIT_FAILURE);
103
    }
104

924,285✔
105
    int size = bufferSize;
924,285✔
106
    int n;
924,285✔
107
    do {
924,285✔
108
        n    = readFile(file, text, 1, size);
924,285✔
109
        text = text + n;
924,285✔
110
        size = size - n;
462,146✔
111
    } while (n>0);
112
    closeFile(file);
462,146✔
113

114
    if (size != 0) {
×
115
        // this is possible, due to <CR><LF> conversion under MS-DOS
×
116
        buffer->allocation.bufferSize -= size;
×
117
        if (size < 0) {
×
118
            char tmpBuffer[TMP_BUFF_SIZE];
×
119
            sprintf(tmpBuffer, "File %s: read %d chars of %d", fileName, bufferSize - size, bufferSize);
120
            editorError(ERR_INTERNAL, tmpBuffer);
121
        }
462,146✔
122
    }
462,146✔
123
    performEncodingAdjustments(buffer);
462,146✔
124
    buffer->modificationTime = modificationTime;
462,146✔
125
    buffer->size = fileSize;
462,146✔
126
    buffer->textLoaded = true;
127
}
128

462,176✔
129
// Should really be in editorbuffer but is dependent on many editor things...
462,176✔
130
void allocateNewEditorBufferTextSpace(EditorBuffer *buffer, int size) {
462,176✔
131
    int minSize = size + EDITOR_ALLOCATION_RESERVE + EDITOR_FREE_PREFIX_SIZE;
462,176✔
132
    int allocIndex = 11;
133
    int allocatedSize = 2048;
134

1,197,909✔
135
    // Ensure size to allocate is at least
735,733✔
136
    for(; allocatedSize<minSize; ) {
735,733✔
137
        allocIndex++;
138
        allocatedSize = allocatedSize << 1;
139
    }
462,176✔
140

462,176✔
141
    char *space = (char *)editorMemory[allocIndex];
3,040✔
142
    if (space == NULL) {
3,040✔
143
        space = malloc(allocatedSize+1);
×
144
        if (space == NULL)
145
            FATAL_ERROR(ERR_NO_MEMORY, "global malloc", EXIT_FAILURE);
3,040✔
146
        // put magic
147
        space[allocatedSize] = 0x3b;
459,136✔
148
    } else {
149
        editorMemory[allocIndex] = editorMemory[allocIndex]->next;
462,176✔
150
    }
151
    buffer->allocation = (EditorBufferAllocationData){.bufferSize = size, .text = space+EDITOR_FREE_PREFIX_SIZE,
152
                                           .allocatedFreePrefixSize = EDITOR_FREE_PREFIX_SIZE,
153
                                           .allocatedBlock = space, .allocatedIndex = allocIndex,
462,176✔
154
                                           .allocatedSize = allocatedSize};
155
}
518✔
156

157
void replaceStringInEditorBuffer(EditorBuffer *buffer, int offset, int deleteSize, char *string,
158
                                 int length, EditorUndo **undoP) {
518✔
159
    assert(offset >=0 && offset <= buffer->allocation.bufferSize);
518✔
160
    assert(deleteSize >= 0);
161
    assert(length >= 0);
162

×
163
    int oldSize = buffer->allocation.bufferSize;
164
    if (deleteSize+offset > oldSize) {
518✔
165
        // deleting over end of buffer,
166
        // delete only until end of buffer
518✔
167
        deleteSize = oldSize - offset;
168
    }
518✔
169
    log_trace("replacing string in buffer %d (%s)", buffer, buffer->fileName);
170

1✔
171
    int newSize = oldSize + length - deleteSize;
172
    // prepare operation
1✔
173
    if (newSize >= buffer->allocation.allocatedSize - buffer->allocation.allocatedFreePrefixSize) {
1✔
174
        // resize buffer
1✔
175
        log_trace("resizing %s from %d(%d) to %d", buffer->fileName, buffer->allocation.bufferSize,
1✔
176
                  buffer->allocation.allocatedSize, newSize);
1✔
177
        char *text = buffer->allocation.text;
1✔
178
        char *space = buffer->allocation.allocatedBlock;
1✔
179
        int index = buffer->allocation.allocatedIndex;
180
        allocateNewEditorBufferTextSpace(buffer, newSize);
181
        memcpy(buffer->allocation.text, text, oldSize);
518✔
182
        buffer->allocation.bufferSize = oldSize;
183
        freeTextSpace(space, index);
302✔
184
    }
302✔
185

302✔
186
    assert(newSize < buffer->allocation.allocatedSize - buffer->allocation.allocatedFreePrefixSize);
302✔
187
    if (undoP!=NULL) {
302✔
188
        // note undo information
302✔
189
        int undoSize = length;
190
        assert(deleteSize >= 0);
191
        char *undoText = malloc(deleteSize+1);
192
        memcpy(undoText, buffer->allocation.text+offset, deleteSize);
518✔
193
        undoText[deleteSize]=0;
518✔
194
        EditorUndo *u = newUndoReplace(buffer, offset, undoSize, deleteSize, undoText, *undoP);
518✔
195
        *undoP = u;
518✔
196
    }
197

198
    // edit text
518✔
199
    memmove(buffer->allocation.text+offset+length, buffer->allocation.text+offset+deleteSize,
178✔
200
            buffer->allocation.bufferSize - offset - deleteSize);
178✔
201
    memcpy(buffer->allocation.text+offset, string, length);
102✔
202
    buffer->allocation.bufferSize = buffer->allocation.bufferSize - deleteSize + length;
203

76✔
204
    // update markers
3,018✔
205
    if (deleteSize > length) {
2,840✔
206
        int pattractor;
1,337✔
207
        if (length > 0)
29✔
208
            pattractor = offset + length - 1;
209
        else
1,308✔
210
            pattractor = offset + length;
211
        for (EditorMarker *m=buffer->markers; m!=NULL; m=m->next) {
212
            if (m->offset >= offset + length) {
213
                if (m->offset < offset+deleteSize) {
214
                    m->offset = pattractor;
5,646✔
215
                } else {
5,306✔
216
                    m->offset = m->offset - deleteSize + length;
2,465✔
217
                }
218
            }
219
        }
220
    } else {
518✔
221
        for (EditorMarker *m=buffer->markers; m!=NULL; m=m->next) {
518✔
222
            if (m->offset >= offset + deleteSize) {
223
                m->offset = m->offset - deleteSize + length;
22✔
224
            }
225
        }
22✔
226
    }
7✔
227
    setEditorBufferModified(buffer);
3✔
228
}
×
229

×
230
void moveBlockInEditorBuffer(EditorMarker *sourceMarker, EditorMarker *destinationMarker, int size,
231
                             EditorUndo **undo) {
22✔
232
    assert(size>=0);
22✔
233
    if (destinationMarker->buffer == sourceMarker->buffer
234
        && destinationMarker->offset > sourceMarker->offset
235
        && destinationMarker->offset < sourceMarker->offset+size) {
22✔
236
        errorMessage(ERR_INTERNAL, "[editor] moving block to its original place");
22✔
237
        return;
22✔
238
    }
239
    EditorBuffer *sourceBuffer = sourceMarker->buffer;
240
    EditorBuffer *destinationBuffer = destinationMarker->buffer;
241

22✔
242
    // insert the block to target position
243
    int destinationOffset = destinationMarker->offset;
244
    int offset1 = sourceMarker->offset;
245
    int offset2 = offset1+size;
22✔
246
    assert(offset1 <= offset2);
22✔
247

22✔
248
    // do it at two steps for the case if source buffer equals target buffer
22✔
249
    // first just allocate space
250
    replaceStringInEditorBuffer(destinationBuffer, destinationOffset, 0, sourceBuffer->allocation.text + offset1,
22✔
251
                                offset2 - offset1, NULL);
252

253
    // now copy text
22✔
254
    offset1 = sourceMarker->offset;
22✔
255
    offset2 = offset1+size;
111✔
256
    replaceStringInEditorBuffer(destinationBuffer, destinationOffset, offset2 - offset1,
89✔
257
                                sourceBuffer->allocation.text + offset1, offset2 - offset1, NULL);
89✔
258
    // save target for undo;
57✔
259
    int undoOffset = sourceMarker->offset;
57✔
260

57✔
261
    // move all markers from moved block
262
    assert(offset1 == sourceMarker->offset);
263
    assert(offset2 == offset1+size);
264
    EditorMarker *mm = sourceBuffer->markers;
265
    while (mm!=NULL) {
22✔
266
        EditorMarker *tmp = mm->next;
267
        if (mm->offset>=offset1 && mm->offset<offset2) {
268
            removeEditorMarkerFromBufferWithoutFreeing(mm);
22✔
269
            mm->offset = destinationOffset + (mm->offset-offset1);
22✔
270
            attachMarkerToBuffer(mm, destinationBuffer);
271
        }
272
        mm = tmp;
22✔
273
    }
15✔
274
    // remove the source block
275
    replaceStringInEditorBuffer(sourceBuffer, offset1, offset2 - offset1, sourceBuffer->allocation.text + offset1,
276
                                0, NULL);
277
    //
278
    setEditorBufferModified(sourceBuffer);
74✔
279
    setEditorBufferModified(destinationBuffer);
74✔
280

74✔
281
    // add the whole operation into undo
74✔
282
    if (undo!=NULL) {
74✔
283
        *undo = newUndoMove(destinationBuffer, sourceMarker->offset, offset2-offset1, sourceBuffer, undoOffset,
74✔
284
                            *undo);
285
    }
126✔
286
}
126✔
287

126✔
288
static void quasiSaveEditorBuffer(EditorBuffer *buffer) {
289
    buffer->modifiedSinceLastQuasiSave = false;
1,316✔
290
    buffer->modificationTime = fileTimestampNow();
2,487✔
291
    FileItem *fileItem = getFileItemWithFileNumber(buffer->fileNumber);
1,297✔
292
    fileItem->lastModified = buffer->modificationTime;
46✔
293
}
46✔
294

295
void quasiSaveModifiedEditorBuffers(void) {
296
    bool          saving            = false;
297
    static FileTimestamp lastQuasiSaveTime = ZERO_TIMESTAMP;
80✔
298

46✔
299
    for (int i = 0; i != -1; i = getNextExistingEditorBufferIndex(i + 1)) {
300
        for (EditorBufferList *ll = getEditorBufferListElementAt(i); ll != NULL; ll = ll->next) {
301
            if (ll->buffer->modifiedSinceLastQuasiSave) {
46✔
302
                saving = true;
46✔
303
                goto cont;
46✔
304
            }
46✔
305
        }
×
306
    }
×
307
cont:
46✔
308
    if (saving) {
38✔
309
        // sychronization, since last quazi save, there must
310
        // be at least one second, otherwise times will be wrong
311
        FileTimestamp currentTime = fileTimestampNow();
1,580✔
312
        long currentSeconds = fileTimestampSeconds(currentTime);
3,000✔
313
        long lastSaveSeconds = fileTimestampSeconds(lastQuasiSaveTime);
1,546✔
314
        if (lastSaveSeconds > currentSeconds + 5) {
74✔
315
            FATAL_ERROR(ERR_INTERNAL, "last save in the future, travelling in time?",
316
                        EXIT_FAILURE);
317
        } else if (lastSaveSeconds >= currentSeconds) {
318
            sleep(1 + lastSaveSeconds - currentSeconds);
126✔
319
        }
126✔
320
    }
321
    for (int i = 0; i != -1; i = getNextExistingEditorBufferIndex(i + 1)) {
63✔
322
        for (EditorBufferList *ll = getEditorBufferListElementAt(i); ll != NULL; ll = ll->next) {
819✔
323
            if (ll->buffer->modifiedSinceLastQuasiSave) {
1,560✔
324
                quasiSaveEditorBuffer(ll->buffer);
804✔
325
            }
74✔
326
        }
74✔
327
    }
328
    lastQuasiSaveTime = fileTimestampNow();
329
}
330

63✔
331
void markModifiedEditorBuffersAsStale(void) {
332
    for (int i = 0; i != -1; i = getNextExistingEditorBufferIndex(i + 1)) {
710✔
333
        for (EditorBufferList *ll = getEditorBufferListElementAt(i); ll != NULL; ll = ll->next) {
3,079✔
334
            if (ll->buffer->modifiedSinceLastQuasiSave) {
4,264✔
335
                FileItem *fi = getFileItemWithFileNumber(ll->buffer->fileNumber);
1,895✔
336
                fi->lastParsedMtime = ZERO_TIMESTAMP;
50✔
337
            }
50✔
338
        }
50✔
339
    }
340
}
341

342
void loadAllOpenedEditorBuffers(void) {
343
    for (int i = 0; i != -1; i = getNextExistingEditorBufferIndex(i + 1)) {
710✔
344
        for (EditorBufferList *l = getEditorBufferListElementAt(i); l != NULL; l = l->next) {
345
            if (!l->buffer->textLoaded) {
307✔
346
                assert(l->buffer->preLoadedFromFile == NULL || l->buffer->preLoadedFromFile != l->buffer->fileName);
307✔
347
                char *fileName = l->buffer->preLoadedFromFile? l->buffer->preLoadedFromFile: l->buffer->fileName;
×
348
                if (fileExists(fileName)) {
307✔
349
                    loadFileIntoEditorBuffer(l->buffer, fileModificationTime(fileName), fileSize(fileName));
350
                    log_trace("loading '%s' into '%s'", fileName, l->buffer->fileName);
351
                }
237✔
352
            }
353
        }
237✔
354
    }
237✔
355
}
237✔
356

237✔
357
static Reference *skipInvisibleReferences(Reference *reference) {
358
    while (reference != NULL && !isVisibleUsage(reference->usage))
54✔
359
        reference = reference->next;
54✔
360
    return reference;
54✔
361
}
362

178✔
363
static void addMarkerAndAdvance(EditorBuffer *buffer, int maxoffset, EditorMarkerList **markerList,
70✔
364
                                Reference **reference) {
70✔
365
    EditorMarker *m = newEditorMarker(buffer, maxoffset);
70✔
366
    *markerList = newEditorMarkerList(m, (*reference)->usage, *markerList);
70✔
367
    *reference = skipInvisibleReferences((*reference)->next);
70✔
368
}
70✔
369

×
370
EditorMarkerList *convertReferencesToEditorMarkers(Reference *references) {
×
371
    EditorMarkerList *markerList = NULL;
×
372
    Reference        *reference = references;
373

70✔
374
    while (reference != NULL) {
70✔
375
        reference = skipInvisibleReferences(reference);
70✔
376
        if (reference != NULL) {
70✔
377
            int           file     = reference->position.file;
378
            FileItem     *fileItem = getFileItemWithFileNumber(file);
70✔
379
            EditorBuffer *buffer   = findOrCreateAndLoadEditorBufferForFile(fileItem->name);
70✔
380
            if (buffer == NULL) {
107,150✔
381
                errorMessage(ERR_CANT_OPEN, fileItem->name);
107,149✔
382
                while (reference != NULL && file == reference->position.file)
383
                    reference = reference->next;
107,080✔
384
            } else {
235✔
385
                char *text      = buffer->allocation.text;
386
                char *smax      = text + buffer->allocation.bufferSize;
107,080✔
387
                int   maxoffset = buffer->allocation.bufferSize - 1;
3,035✔
388
                if (maxoffset < 0)
3,035✔
389
                    maxoffset = 0;
390
                int line = 1;
391
                int col  = 0;
392
                for (; text < smax; text++, col++) {
393
                    if (reference == NULL || file != reference->position.file)
394
                        break;
395
                    if (line == reference->position.line && col == reference->position.col) {
1✔
396
                        addMarkerAndAdvance(buffer, text - buffer->allocation.text, &markerList, &reference);
397
                    }
3,035✔
398
                    if (*text == '\n') {
3,035✔
399
                        if (reference != NULL && file == reference->position.file
400
                            && line == reference->position.line) {
401
                            /* col unreachable on this line — clamp marker to
402
                             * current (end-of-line) position and advance to
71✔
403
                             * the next reference. Mirrors the past-EOF
1✔
404
                             * fallback below, but caught at line scope to
405
                             * avoid the cascade where one stuck ref dooms
406
                             * every subsequent ref to maxoffset. */
407
                            addMarkerAndAdvance(buffer, text - buffer->allocation.text, &markerList, &reference);
408
                        }
409
                        line++;
410
                        col = -1;
291✔
411
                    }
54✔
412
                }
413
                // references beyond end of buffer
414
                while (reference != NULL && file == reference->position.file) {
×
415
                    addMarkerAndAdvance(buffer, maxoffset, &markerList, &reference);
×
416
                }
417
            }
418
        }
2✔
419
    }
420
    // get markers in the same order as were references
421
    // ?? is this still needed?
2✔
422
    LIST_REVERSE(EditorMarkerList, markerList);
2✔
423
    return markerList;
3✔
424
}
1✔
425

1✔
426
static int referencePositionComparer(Reference *r1, Reference *r2) {
1✔
427
    return positionIsLessThan(r1->position, r2->position);
1✔
428
}
1✔
429

1✔
430
Reference *convertEditorMarkersToReferences(EditorMarkerList **editorMarkerListP) {
825✔
431

825✔
432
    LIST_MERGE_SORT(EditorMarkerList, *editorMarkerListP, editorMarkerListBefore);
1✔
433

1✔
434
    Reference *reference = NULL;
435
    EditorMarkerList *markers = *editorMarkerListP;
×
436
    while (markers!=NULL) {
437
        EditorBuffer *buffer = markers->marker->buffer;
824✔
438
        char *text = buffer->allocation.text;
32✔
439
        char *textMax = text + buffer->allocation.bufferSize;
32✔
440
        char *offset = buffer->allocation.text + markers->marker->offset;
441
        int line = 1;
442
        int col = 0;
×
443
        for (; text<textMax; text++, col++) {
×
444
            if (text == offset) {
445
                reference = newReference((Position){buffer->fileNumber, line, col}, markers->usage, reference);
446
                markers = markers->next;
2✔
447
                if (markers==NULL || markers->marker->buffer != buffer)
448
                    break;
449
                offset = buffer->allocation.text + markers->marker->offset;
450
            }
451
            if (*text=='\n') {
452
                line++;
453
                col = -1;
454
            }
455
        }
456
        while (markers!=NULL && markers->marker->buffer==buffer) {
457
            reference = newReference((Position){buffer->fileNumber, line, 0}, markers->usage, reference);
458
            markers = markers->next;
459
        }
460
    }
461
    LIST_MERGE_SORT(Reference, reference, referencePositionComparer);
462
    return reference;
463
}
464

465
#if 0
466
void editorDumpBuffer(EditorBuffer *buff) {
467
    /* TODO: Should really put this in log() */
468
    for (int i=0; i<buff->allocation.bufferSize; i++) {
469
        putc(buff->allocation.text[i], errOut);
470
    }
471
}
472

473
void editorDumpUndoList(EditorUndo *undo) {
474
    log_trace("[dumping editor undo list]");
475
    while (undo != NULL) {
476
        switch (undo->operation) {
477
        case UNDO_REPLACE_STRING:
478
            log_trace("replace string [%s:%d] %d (%ld)%s %d", undo->buffer->name, undo->u.replace.offset,
479
                      undo->u.replace.size, (unsigned long)undo->u.replace.str, undo->u.replace.str,
480
                      undo->u.replace.strlen);
481
            if (strlen(undo->u.replace.str) != undo->u.replace.strlen)
482
                log_trace("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
483
            break;
484
        case UNDO_RENAME_BUFFER:
5,626✔
485
            log_trace("rename buffer %s %s", undo->buffer->name, undo->u.rename.name);
5,626✔
486
            break;
253,128✔
487
        case UNDO_MOVE_BLOCK:
707,391✔
488
            log_trace("move block [%s:%d] [%s:%d] size==%d", undo->buffer->name, undo->u.moveBlock.offset,
459,889✔
489
                      undo->u.moveBlock.dbuffer->name, undo->u.moveBlock.doffset, undo->u.moveBlock.size);
459,889✔
490
            break;
459,889✔
491
        default:
459,889✔
492
            errorMessage(ERR_INTERNAL, "Unknown operation to undo");
493
        }
494
        undo = undo->next;
5,626✔
495
    }
496
    log_trace("[undodump] end");
497
}
5,626✔
498
#endif
5,626✔
499

465,515✔
500
static EditorBufferList *computeListOfAllEditorBuffers(void) {
459,889✔
501
    EditorBufferList *list = NULL;
459,889✔
502
    for (int i=0; i != -1 ; i = getNextExistingEditorBufferIndex(i+1)) {
459,889✔
503
        for (EditorBufferList *l = getEditorBufferListElementAt(i); l != NULL; l = l->next) {
504
            EditorBufferList *element;
5,626✔
505
            element = malloc(sizeof(EditorBufferList));
506
            *element = (EditorBufferList){.buffer = l->buffer, .next = list};
×
507
            list     = element;
×
508
        }
509
    }
510
    return list;
6✔
511
}
6✔
512

6✔
513
static void freeEditorBufferListButNotBuffers(EditorBufferList *list) {
6✔
514
    EditorBufferList *l = list;
2✔
515
    while (l!=NULL) {
516
        EditorBufferList *n = l->next;
517
        free(l);
518
        l = n;
519
    }
520
}
516✔
521

522
static int editorBufferNameLess(EditorBufferList*l1, EditorBufferList*l2) {
523
    return strcmp(l1->buffer->fileName, l2->buffer->fileName);
524
}
525

526
static bool directoryPrefixMatches(char *fileName, char *dirname) {
527
    int dirNameLength = strlen(dirname);
528
    return filenameCompare(fileName, dirname, dirNameLength) == 0
529
        && (fileName[dirNameLength] == '/'
530
            || fileName[dirNameLength] == '\\');
531
}
532

516✔
533
// TODO, do all this stuff better!
534
// This is still quadratic on number of opened buffers
516✔
535
// for recursive search
536
bool editorMapOnNonExistantFiles(char *dirname,
516✔
537
                                void (*fun)(MAP_FUN_SIGNATURE),
522✔
538
                                SearchDepth depth,
6✔
539
                                char *a1,
2✔
540
                                char *a2,
2✔
541
                                Completions *a3,
2✔
542
                                void *a4,
2✔
543
                                int *a5
×
544
) {
×
545
    // In order to avoid mapping of the same directory several
×
546
    // times, first just create list of all files, sort it, and then
×
547
    // map them
×
548
    EditorBufferList *listOfAllBuffers   = computeListOfAllEditorBuffers();
×
549
    LIST_MERGE_SORT(EditorBufferList, listOfAllBuffers, editorBufferNameLess);
550

×
551
    EditorBufferList *list = listOfAllBuffers;
×
552

×
553
    bool found = false;
554
    while(list!=NULL) {
555
        if (directoryPrefixMatches(list->buffer->fileName, dirname)) {
2✔
556
            int dirNameLength = strlen(dirname);
2✔
557
            char fname[MAX_FILE_NAME_SIZE];
558
            int fileNameLength;
559
            if (depth == DEPTH_ONE) {
2✔
560
                char *pathDelimiter = strchr(list->buffer->fileName+dirNameLength+1, '/');
561
                if (pathDelimiter==NULL)
×
562
                    pathDelimiter = strchr(list->buffer->fileName+dirNameLength+1, '\\');
×
563
                if (pathDelimiter==NULL) {
564
                    strcpy(fname, list->buffer->fileName+dirNameLength+1);
×
565
                    fileNameLength = strlen(fname);
×
566
                } else {
×
567
                    fileNameLength = pathDelimiter-(list->buffer->fileName+dirNameLength+1);
×
568
                    strncpy(fname, list->buffer->fileName+dirNameLength+1, fileNameLength);
×
569
                    fname[fileNameLength]=0;
×
570
                }
×
571
            } else {
572
                strcpy(fname, list->buffer->fileName+dirNameLength+1);
573
                fileNameLength = strlen(fname);
2✔
574
            }
575
            // Only map on nonexistant files
576
            if (!fileExists(list->buffer->fileName)) {
4✔
577
                // get file name
578
                (*fun)(fname, a1, a2, a3, a4, a5);
579
                found = true;
516✔
580
                // skip all files in the same directory
581
                char *lastMapped = list->buffer->fileName;
516✔
582
                int lastMappedLength = dirNameLength+1+fileNameLength;
583
                list = list->next;
584
                while (list!=NULL
462,169✔
585
                       && filenameCompare(list->buffer->fileName, lastMapped, lastMappedLength)==0
462,169✔
586
                       && (list->buffer->fileName[lastMappedLength]=='/' || list->buffer->fileName[lastMappedLength]=='\\')) {
462,098✔
587
                    list = list->next;
924,164✔
588
                }
589
            } else {
590
                list = list->next;
3,632✔
591
            }
3,632✔
592
        } else {
3,632✔
593
            list = list->next;
3,630✔
594
        }
3,632✔
595
    }
3,632✔
596
    freeEditorBufferListButNotBuffers(listOfAllBuffers);
597

4,038✔
598
    return found;
4,038✔
599
}
462,575✔
600

458,537✔
601
static bool bufferIsCloseable(EditorBuffer *buffer) {
458,340✔
602
    return buffer != NULL && buffer->textLoaded && buffer->markers==NULL
603
        && buffer->preLoadedFromFile == NULL  /* not -preloaded */
458,340✔
604
        && ! buffer->modified;
458,340✔
605
}
606

607
void closeEditorBufferIfCloseable(char *name) {
4,038✔
608
    EditorBuffer *buffer = findOrCreateAndLoadEditorBufferForFile(name);
4,038✔
609
    if (bufferIsCloseable(buffer))
610
        deregisterEditorBuffer(name);
529✔
611
    freeEditorBuffer(buffer);
529✔
612
}
724✔
613

195✔
614
void closeAllEditorBuffersIfClosable(void) {
615
    EditorBufferList *allEditorBuffers = computeListOfAllEditorBuffers();
529✔
616
    for (EditorBufferList *l = allEditorBuffers; l!=NULL; l=l->next) {
529✔
617
        if (bufferIsCloseable(l->buffer)) {
618
            log_trace("closable %d for '%s'='%s'", bufferIsCloseable(l->buffer),
543✔
619
                      l->buffer->preLoadedFromFile?l->buffer->preLoadedFromFile:"(null)", l->buffer->fileName);
543✔
620
            EditorBuffer *buffer = deregisterEditorBuffer(l->buffer->fileName);
1,694✔
621
            freeEditorBuffer(buffer);
1,151✔
622
        }
19✔
623
    }
19✔
624
    freeEditorBufferListButNotBuffers(allEditorBuffers);
19✔
625
}
19✔
626

627
void clearPreloadedThisRequestFlags(void) {
628
    EditorBufferList *allEditorBuffers = computeListOfAllEditorBuffers();
629
    for (EditorBufferList *l = allEditorBuffers; l != NULL; l = l->next) {
630
        l->buffer->preloadedThisRequest = false;
19✔
631
    }
632
    freeEditorBufferListButNotBuffers(allEditorBuffers);
633
}
543✔
634

543✔
635
void closeEditorBuffersNoLongerPreloaded(ArgumentsVector baseArgs) {
636
    EditorBufferList *allEditorBuffers = computeListOfAllEditorBuffers();
637
    for (EditorBufferList *l = allEditorBuffers; l != NULL; l = l->next) {
638
        if (isPreloaded(l->buffer) && !l->buffer->preloadedThisRequest) {
639
            log_trace("Closing ghost preloaded buffer '%s' (fileNumber=%d)", l->buffer->fileName, l->buffer->fileNumber);
640
            int fileNumber = l->buffer->fileNumber;
641
            EditorBuffer *buffer = deregisterEditorBuffer(l->buffer->fileName);
642
            freeEditorBuffer(buffer);
643
            /* Refresh the file's references from disk content, since
644
             * the editor's view is no longer authoritative. For a CU
645
             * this re-parses the file; for a header it strips refs and
646
             * relies on a CU includer's reparse to re-emit them. */
647
            reparseFile(fileNumber, baseArgs);
648
        }
649
    }
650
    freeEditorBufferListButNotBuffers(allEditorBuffers);
651
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc