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

thoni56 / c-xrefactory / 1676

24 Dec 2025 09:07AM UTC coverage: 82.868% (+0.1%) from 82.747%
1676

push

travis-ci

thoni56
[ci] Reverting cgreen version on travis to 1.6.1

13234 of 15970 relevant lines covered (82.87%)

17959982.44 hits per line

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

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

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

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

20

21
typedef struct editorMemoryBlock {
22
    struct editorMemoryBlock *next;
23
} EditorMemoryBlock;
24

25

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

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

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

38

39
void editorInit(void) {
149✔
40
    initEditorBufferTable();
149✔
41
}
149✔
42

43
time_t editorFileModificationTime(char *path) {
1,011,460✔
44
    EditorBuffer *buffer;
45

46
    buffer = getEditorBufferForFile(path);
1,011,460✔
47
    if (buffer != NULL)
1,011,460✔
48
        return buffer->modificationTime;
1,007,304✔
49
    return fileModificationTime(path);
4,156✔
50
}
51

52
size_t editorFileSize(char *path) {
46✔
53
    EditorBuffer *buffer;
54

55
    buffer = getEditorBufferForFile(path);
46✔
56
    if (buffer != NULL)
46✔
57
        return buffer->size;
×
58
    return fileSize(path);
46✔
59
}
60

61
bool editorFileExists(char *path) {
1,023,174✔
62
    EditorBuffer *buffer;
63

64
    buffer = getEditorBufferForFile(path);
1,023,174✔
65
    if (buffer != NULL)
1,023,174✔
66
        return true;
1,007,442✔
67
    return fileExists(path);
15,732✔
68
}
69

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

74
void freeTextSpace(char *space, int index) {
458,945✔
75
    EditorMemoryBlock *sp;
76
    sp = (EditorMemoryBlock *) space;
458,945✔
77
    sp->next = editorMemory[index];
458,945✔
78
    editorMemory[index] = sp;
458,945✔
79
}
458,945✔
80

81
void loadTextIntoEditorBuffer(EditorBuffer *buffer, time_t modificationTime, const char *text) {
×
82
    allocateNewEditorBufferTextSpace(buffer, strlen(text));
×
83
    strcpy(buffer->allocation.text, text);
×
84
}
85

86
void loadFileIntoEditorBuffer(EditorBuffer *buffer, time_t modificationTime, size_t fileSize) {
459,307✔
87
    allocateNewEditorBufferTextSpace(buffer, fileSize);
459,307✔
88

89
    char *text = buffer->allocation.text;
459,307✔
90
    assert(text != NULL);
91

459,307✔
92
    assert(buffer->preLoadedFromFile == NULL || buffer->preLoadedFromFile != buffer->fileName);
459,307✔
93
    int bufferSize = buffer->allocation.bufferSize;
94
    char *fileName = buffer->preLoadedFromFile? buffer->preLoadedFromFile: buffer->fileName;
459,307✔
95

96
    log_trace(":loading file %s==%s size %d", fileName, buffer->fileName, bufferSize);
459,307✔
97

459,307✔
98
    FILE *file = openFile(fileName, "r");
×
99
    if (file == NULL) {
100
        FATAL_ERROR(ERR_CANT_OPEN, fileName, XREF_EXIT_ERR);
101
    }
459,307✔
102

103
    int size = bufferSize;
104
    int n;
918,607✔
105
    do {
918,607✔
106
        n    = readFile(file, text, 1, size);
918,607✔
107
        text = text + n;
918,607✔
108
        size = size - n;
459,307✔
109
    } while (n>0);
110
    closeFile(file);
459,307✔
111

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

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

1,191,648✔
133
    // Ensure size to allocate is at least
732,333✔
134
    for(; allocatedSize<minSize; ) {
732,333✔
135
        allocIndex++;
136
        allocatedSize = allocatedSize << 1;
137
    }
459,315✔
138

459,315✔
139
    char *space = (char *)editorMemory[allocIndex];
2,454✔
140
    if (space == NULL) {
2,454✔
141
        space = malloc(allocatedSize+1);
×
142
        if (space == NULL)
143
            FATAL_ERROR(ERR_NO_MEMORY, "global malloc", XREF_EXIT_ERR);
2,454✔
144
        // put magic
145
        space[allocatedSize] = 0x3b;
456,861✔
146
    } else {
147
        editorMemory[allocIndex] = editorMemory[allocIndex]->next;
459,315✔
148
    }
149
    buffer->allocation = (EditorBufferAllocationData){.bufferSize = size, .text = space+EDITOR_FREE_PREFIX_SIZE,
150
                                           .allocatedFreePrefixSize = EDITOR_FREE_PREFIX_SIZE,
151
                                           .allocatedBlock = space, .allocatedIndex = allocIndex,
459,315✔
152
                                           .allocatedSize = allocatedSize};
153
}
188✔
154

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

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

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

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

196
    // edit text
188✔
197
    memmove(buffer->allocation.text+offset+length, buffer->allocation.text+offset+deleteSize,
198
            buffer->allocation.bufferSize - offset - deleteSize);
66✔
199
    memcpy(buffer->allocation.text+offset, string, length);
39✔
200
    buffer->allocation.bufferSize = buffer->allocation.bufferSize - deleteSize + length;
201

27✔
202
    // update markers
492✔
203
    if (deleteSize > length) {
426✔
204
        int pattractor;
167✔
205
        if (length > 0)
13✔
206
            pattractor = offset + length - 1;
207
        else
154✔
208
            pattractor = offset + length;
209
        for (EditorMarker *m=buffer->markers; m!=NULL; m=m->next) {
210
            if (m->offset >= offset + length) {
211
                if (m->offset < offset+deleteSize) {
212
                    m->offset = pattractor;
657✔
213
                } else {
535✔
214
                    m->offset = m->offset - deleteSize + length;
181✔
215
                }
216
            }
217
        }
218
    } else {
188✔
219
        for (EditorMarker *m=buffer->markers; m!=NULL; m=m->next) {
188✔
220
            if (m->offset >= offset + deleteSize) {
221
                m->offset = m->offset - deleteSize + length;
1✔
222
            }
223
        }
1✔
224
    }
1✔
225
    setEditorBufferModified(buffer);
×
226
}
×
227

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

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

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

251
    // now copy text
1✔
252
    offset1 = sourceMarker->offset;
3✔
253
    offset2 = offset1+size;
2✔
254
    replaceStringInEditorBuffer(destinationBuffer, destinationOffset, offset2 - offset1,
2✔
255
                                sourceBuffer->allocation.text + offset1, offset2 - offset1, NULL);
1✔
256
    // save target for undo;
1✔
257
    int undoOffset = sourceMarker->offset;
1✔
258

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

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

286
static void quasiSaveEditorBuffer(EditorBuffer *buffer) {
429✔
287
    buffer->modifiedSinceLastQuasiSave = false;
698✔
288
    buffer->modificationTime = time(NULL);
343✔
289
    FileItem *fileItem = getFileItemWithFileNumber(buffer->fileNumber);
23✔
290
    fileItem->lastModified = buffer->modificationTime;
23✔
291
}
292

293
void quasiSaveModifiedEditorBuffers(void) {
294
    bool          saving            = false;
51✔
295
    static time_t lastQuasiSaveTime = 0;
74✔
296

297
    for (int i = 0; i != -1; i = getNextExistingEditorBufferIndex(i + 1)) {
298
        for (EditorBufferList *ll = getEditorBufferListElementAt(i); ll != NULL; ll = ll->next) {
23✔
299
            if (ll->buffer->modifiedSinceLastQuasiSave) {
23✔
300
                saving = true;
×
301
                goto cont;
302
            }
23✔
303
        }
×
304
    }
305
cont:
306
    if (saving) {
504✔
307
        // sychronization, since last quazi save, there must
832✔
308
        // be at least one second, otherwise times will be wrong
402✔
309
        time_t currentTime = time(NULL);
30✔
310
        if (lastQuasiSaveTime > currentTime + 5) {
311
            FATAL_ERROR(ERR_INTERNAL, "last save in the future, travelling in time?",
312
                        XREF_EXIT_ERR);
313
        } else if (lastQuasiSaveTime >= currentTime) {
74✔
314
            sleep(1 + lastQuasiSaveTime - currentTime);
74✔
315
        }
316
    }
389✔
317
    for (int i = 0; i != -1; i = getNextExistingEditorBufferIndex(i + 1)) {
1,436✔
318
        for (EditorBufferList *ll = getEditorBufferListElementAt(i); ll != NULL; ll = ll->next) {
1,784✔
319
            if (ll->buffer->modifiedSinceLastQuasiSave) {
737✔
320
                quasiSaveEditorBuffer(ll->buffer);
11✔
321
            }
11✔
322
        }
11✔
323
    }
324
    lastQuasiSaveTime = time(NULL);
325
}
326

327
void loadAllOpenedEditorBuffers(void) {
389✔
328
    for (int i = 0; i != -1; i = getNextExistingEditorBufferIndex(i + 1)) {
329
        for (EditorBufferList *l = getEditorBufferListElementAt(i); l != NULL; l = l->next) {
×
330
            if (!l->buffer->textLoaded) {
×
331
                assert(l->buffer->preLoadedFromFile == NULL || l->buffer->preLoadedFromFile != l->buffer->fileName);
×
332
                char *fileName = l->buffer->preLoadedFromFile? l->buffer->preLoadedFromFile: l->buffer->fileName;
×
333
                if (fileExists(fileName)) {
×
334
                    loadFileIntoEditorBuffer(l->buffer, fileModificationTime(fileName), fileSize(fileName));
×
335
                    log_trace("loading '%s' into '%s'", fileName, l->buffer->fileName);
×
336
                }
×
337
            }
×
338
        }
×
339
    }
340
}
341

×
342
void removeBlanksAtEditorMarker(EditorMarker *marker, int direction, EditorUndo **undo) {
×
343
    int offset = marker->offset;
×
344
    if (direction < 0) {
×
345
        marker->offset--;
×
346
        moveEditorMarkerToNonBlank(marker, -1);
×
347
        marker->offset++;
348
        replaceStringInEditorBuffer(marker->buffer, marker->offset, offset - marker->offset, "", 0, undo);
349
    } else if (direction > 0) {
350
        moveEditorMarkerToNonBlank(marker, 1);
65✔
351
        replaceStringInEditorBuffer(marker->buffer, offset, marker->offset - offset, "", 0, undo);
65✔
352
    } else {
65✔
353
        // both directions
354
        marker->offset --;
140✔
355
        moveEditorMarkerToNonBlank(marker, -1);
75✔
356
        marker->offset++;
×
357
        offset = marker->offset;
75✔
358
        moveEditorMarkerToNonBlank(marker, 1);
75✔
359
        replaceStringInEditorBuffer(marker->buffer, offset, marker->offset - offset, "", 0, undo);
75✔
360
    }
75✔
361
}
75✔
362

75✔
363
EditorMarkerList *convertReferencesToEditorMarkers(Reference *references) {
75✔
364
    EditorMarkerList *markerList = NULL;
×
365
    Reference        *reference = references;
×
366

×
367
    while (reference != NULL) {
368
        while (reference != NULL && !isVisibleUsage(reference->usage))
75✔
369
            reference = reference->next;
75✔
370
        if (reference != NULL) {
75✔
371
            int           file     = reference->position.file;
75✔
372
            int           line     = reference->position.line;
1✔
373
            int           col      = reference->position.col;
75✔
374
            FileItem     *fileItem = getFileItemWithFileNumber(file);
75✔
375
            EditorBuffer *buff     = findOrCreateAndLoadEditorBufferForFile(fileItem->name);
157,512✔
376
            if (buff == NULL) {
157,511✔
377
                errorMessage(ERR_CANT_OPEN, fileItem->name);
175✔
378
                while (reference != NULL && file == reference->position.file)
175✔
379
                    reference = reference->next;
175✔
380
            } else {
175✔
381
                char *text      = buff->allocation.text;
175✔
382
                char *smax      = text + buff->allocation.bufferSize;
×
383
                int   maxoffset = buff->allocation.bufferSize - 1;
175✔
384
                if (maxoffset < 0)
385
                    maxoffset = 0;
101✔
386
                int l = 1;
101✔
387
                int c  = 0;
388
                for (; text < smax; text++, c++) {
157,437✔
389
                    if (l == line && c == col) {
4,410✔
390
                        EditorMarker *m    = newEditorMarker(buff, text - buff->allocation.text);
4,410✔
391
                        EditorMarkerList *rrr  = newEditorMarkerList(m, reference->usage, markerList);
392
                        markerList  = rrr;
393
                        reference    = reference->next;
394
                        while (reference != NULL && !isVisibleUsage(reference->usage))
76✔
395
                            reference = reference->next;
1✔
396
                        if (reference == NULL || file != reference->position.file)
1✔
397
                            break;
1✔
398
                        line = reference->position.line;
1✔
399
                        col  = reference->position.col;
×
400
                    }
401
                    if (*text == '\n') {
402
                        l++;
403
                        c = -1;
404
                    }
405
                }
406
                // references beyond end of buffer
241✔
407
                while (reference != NULL && file == reference->position.file) {
65✔
408
                    EditorMarker *m    = newEditorMarker(buff, maxoffset);
409
                    EditorMarkerList *rrr  = newEditorMarkerList(m, reference->usage, markerList);
410
                    markerList  = rrr;
×
411
                    reference    = reference->next;
×
412
                    while (reference != NULL && !isVisibleUsage(reference->usage))
413
                        reference = reference->next;
414
                }
2✔
415
            }
416
        }
417
    }
2✔
418
    // get markers in the same order as were references
2✔
419
    // ?? is this still needed?
3✔
420
    LIST_REVERSE(EditorMarkerList, markerList);
1✔
421
    return markerList;
1✔
422
}
1✔
423

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

825✔
428
Reference *convertEditorMarkersToReferences(EditorMarkerList **editorMarkerListP) {
1✔
429

1✔
430
    LIST_MERGE_SORT(EditorMarkerList, *editorMarkerListP, editorMarkerListBefore);
431

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

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

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

455,465✔
498
static EditorBufferList *computeListOfAllEditorBuffers(void) {
455,465✔
499
    EditorBufferList *list = NULL;
500
    for (int i=0; i != -1 ; i = getNextExistingEditorBufferIndex(i+1)) {
4,167✔
501
        for (EditorBufferList *l = getEditorBufferListElementAt(i); l != NULL; l = l->next) {
502
            EditorBufferList *element;
237✔
503
            element = malloc(sizeof(EditorBufferList));
237✔
504
            *element = (EditorBufferList){.buffer = l->buffer, .next = list};
505
            list     = element;
506
        }
114✔
507
    }
114✔
508
    return list;
114✔
509
}
114✔
510

×
511
static void freeEditorBufferListButNotBuffers(EditorBufferList *list) {
512
    EditorBufferList *l = list;
513
    while (l!=NULL) {
514
        EditorBufferList *n = l->next;
515
        free(l);
516
        l = n;
428✔
517
    }
518
}
519

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

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

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

×
549
    EditorBufferList *list = listOfAllBuffers;
550

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

457,779✔
596
    return found;
454,186✔
597
}
598

454,184✔
599
static bool bufferIsCloseable(EditorBuffer *buffer) {
454,184✔
600
    return buffer != NULL && buffer->textLoaded && buffer->markers==NULL
601
        && buffer->preLoadedFromFile == NULL  /* not -preloaded */
602
        && ! buffer->modified;
3,593✔
603
}
3,593✔
604

605
void closeEditorBufferIfCloseable(char *name) {
146✔
606
    EditorBuffer *buffer = findOrCreateAndLoadEditorBufferForFile(name);
146✔
607
    if (bufferIsCloseable(buffer))
1,311✔
608
        deregisterEditorBuffer(name);
1,165✔
609
    freeEditorBuffer(buffer);
1,165✔
610
}
611

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

625
void closeAllEditorBuffers(void) {
626
    EditorBufferList *allEditorBuffers = computeListOfAllEditorBuffers();
627
    for (EditorBufferList *l = allEditorBuffers; l!=NULL; l=l->next) {
628
        EditorBuffer *buffer = deregisterEditorBuffer(l->buffer->fileName);
629
        freeEditorBuffer(buffer);
630
    }
631
    freeEditorBufferListButNotBuffers(allEditorBuffers);
632
}
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