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

thoni56 / c-xrefactory / 1617

19 Nov 2025 11:56PM UTC coverage: 81.092% (+54.7%) from 26.404%
1617

push

travis-ci

thoni56
[tests] Trying to get C11 test more platform independent

The output is the references but they vary depending on the standard include design.

12836 of 15829 relevant lines covered (81.09%)

1769773.98 hits per line

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

81.74
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
#include "editorbuffertable.h"
39

40

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

45
time_t editorFileModificationTime(char *path) {
31,415✔
46
    EditorBuffer *buffer;
47

48
    buffer = getEditorBufferForFile(path);
31,415✔
49
    if (buffer != NULL)
31,415✔
50
        return buffer->modificationTime;
27,406✔
51
    return fileModificationTime(path);
4,009✔
52
}
53

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

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

63
bool editorFileExists(char *path) {
41,739✔
64
    EditorBuffer *buffer;
65

66
    buffer = getEditorBufferForFile(path);
41,739✔
67
    if (buffer != NULL)
41,739✔
68
        return true;
27,534✔
69
    return fileExists(path);
14,205✔
70
}
71

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

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

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

88
void loadFileIntoEditorBuffer(EditorBuffer *buffer, time_t modificationTime, size_t fileSize) {
20,471✔
89
    allocateNewEditorBufferTextSpace(buffer, fileSize);
20,471✔
90

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

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

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

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

105
    int size = bufferSize;
106
    int n;
40,937✔
107
    do {
40,937✔
108
        n    = readFile(file, text, 1, size);
40,937✔
109
        text = text + n;
40,937✔
110
        size = size - n;
20,471✔
111
    } while (n>0);
112
    closeFile(file);
20,471✔
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
        }
20,471✔
122
    }
20,471✔
123
    performEncodingAdjustments(buffer);
20,471✔
124
    buffer->modificationTime = modificationTime;
20,471✔
125
    buffer->size = fileSize;
20,471✔
126
    buffer->textLoaded = true;
127
}
128

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

72,325✔
135
    // Ensure size to allocate is at least
51,846✔
136
    for(; allocatedSize<minSize; ) {
51,846✔
137
        allocIndex++;
138
        allocatedSize = allocatedSize << 1;
139
    }
20,479✔
140

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

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

×
163
    int oldSize = buffer->allocation.bufferSize;
164
    if (deleteSize+offset > oldSize) {
188✔
165
        // deleting over end of buffer,
166
        // delete only until end of buffer
188✔
167
        deleteSize = oldSize - offset;
168
    }
188✔
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);
188✔
182
        buffer->allocation.bufferSize = oldSize;
183
        freeTextSpace(space, index);
124✔
184
    }
124✔
185

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

825✔
426
Reference *convertEditorMarkersToReferences(EditorMarkerList **editorMarkerListP) {
1✔
427

1✔
428
    LIST_MERGE_SORT(EditorMarkerList, *editorMarkerListP, editorMarkerListBefore);
429

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

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

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

16,752✔
496
static EditorBufferList *computeListOfAllEditorBuffers(void) {
16,752✔
497
    EditorBufferList *list = NULL;
498
    for (int i=0; i != -1 ; i = getNextExistingEditorBufferIndex(i+1)) {
3,982✔
499
        for (EditorBufferList *l = getEditorBufferListElementAt(i); l != NULL; l = l->next) {
500
            EditorBufferList *element;
237✔
501
            element = malloc(sizeof(EditorBufferList));
237✔
502
            *element = (EditorBufferList){.buffer = l->buffer, .next = list};
503
            list     = element;
504
        }
108✔
505
    }
108✔
506
    return list;
108✔
507
}
108✔
508

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

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

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

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

×
547
    EditorBufferList *list = listOfAllBuffers;
548

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

16,232✔
594
    return found;
595
}
16,232✔
596

16,232✔
597
static bool bufferIsCloseable(EditorBuffer *buffer) {
598
    return buffer != NULL && buffer->textLoaded && buffer->markers==NULL
599
        && buffer->preLoadedFromFile == NULL  /* not -preloaded */
3,462✔
600
        && ! buffer->modified;
3,462✔
601
}
602

129✔
603
void closeEditorBufferIfCloseable(char *name) {
129✔
604
    EditorBuffer *buffer = findOrCreateAndLoadEditorBufferForFile(name);
541✔
605
    if (bufferIsCloseable(buffer))
412✔
606
        deregisterEditorBuffer(name);
412✔
607
    freeEditorBuffer(buffer);
608
}
129✔
609

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

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