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

thoni56 / c-xrefactory / 1721

06 Feb 2026 08:14AM UTC coverage: 81.393% (+0.07%) from 81.319%
1721

push

travis-ci

thoni56
[tidy] And extract a better function

14720 of 18085 relevant lines covered (81.39%)

16166055.02 hits per line

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

82.54
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 "undo.h"
17
#include "usage.h"
18

19

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

24

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

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

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

37

38
void editorInit(void) {
191✔
39
    initEditorBufferTable();
191✔
40
}
191✔
41

42
time_t editorFileModificationTime(char *path) {
1,022,149✔
43
    EditorBuffer *buffer;
44

45
    buffer = getEditorBufferForFile(path);
1,022,149✔
46
    if (buffer != NULL)
1,022,149✔
47
        return buffer->modificationTime;
1,014,325✔
48
    return fileModificationTime(path);
7,824✔
49
}
50

51
size_t editorFileSize(char *path) {
83✔
52
    EditorBuffer *buffer;
53

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

60
bool editorFileExists(char *path) {
1,034,542✔
61
    EditorBuffer *buffer;
62

63
    buffer = getEditorBufferForFile(path);
1,034,542✔
64
    if (buffer != NULL)
1,034,542✔
65
        return true;
1,014,531✔
66
    return fileExists(path);
20,011✔
67
}
68

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

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

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

85
void loadFileIntoEditorBuffer(EditorBuffer *buffer, time_t modificationTime, size_t fileSize) {
460,636✔
86
    allocateNewEditorBufferTextSpace(buffer, fileSize);
460,636✔
87

88
    char *text = buffer->allocation.text;
460,636✔
89
    assert(text != NULL);
90

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

95
    log_trace(":loading file %s==%s size %d", fileName, buffer->fileName, bufferSize);
460,636✔
96

460,636✔
97
    FILE *file = openFile(fileName, "r");
×
98
    if (file == NULL) {
99
        FATAL_ERROR(ERR_CANT_OPEN, fileName, EXIT_FAILURE);
100
    }
460,636✔
101

102
    int size = bufferSize;
103
    int n;
921,264✔
104
    do {
921,264✔
105
        n    = readFile(file, text, 1, size);
921,264✔
106
        text = text + n;
921,264✔
107
        size = size - n;
460,636✔
108
    } while (n>0);
109
    closeFile(file);
460,636✔
110

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

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

1,194,793✔
132
    // Ensure size to allocate is at least
734,146✔
133
    for(; allocatedSize<minSize; ) {
734,146✔
134
        allocIndex++;
135
        allocatedSize = allocatedSize << 1;
136
    }
460,647✔
137

460,647✔
138
    char *space = (char *)editorMemory[allocIndex];
2,544✔
139
    if (space == NULL) {
2,544✔
140
        space = malloc(allocatedSize+1);
×
141
        if (space == NULL)
142
            FATAL_ERROR(ERR_NO_MEMORY, "global malloc", EXIT_FAILURE);
2,544✔
143
        // put magic
144
        space[allocatedSize] = 0x3b;
458,103✔
145
    } else {
146
        editorMemory[allocIndex] = editorMemory[allocIndex]->next;
460,647✔
147
    }
148
    buffer->allocation = (EditorBufferAllocationData){.bufferSize = size, .text = space+EDITOR_FREE_PREFIX_SIZE,
149
                                           .allocatedFreePrefixSize = EDITOR_FREE_PREFIX_SIZE,
150
                                           .allocatedBlock = space, .allocatedIndex = allocIndex,
460,647✔
151
                                           .allocatedSize = allocatedSize};
152
}
443✔
153

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

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

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

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

195
    // edit text
443✔
196
    memmove(buffer->allocation.text+offset+length, buffer->allocation.text+offset+deleteSize,
197
            buffer->allocation.bufferSize - offset - deleteSize);
159✔
198
    memcpy(buffer->allocation.text+offset, string, length);
94✔
199
    buffer->allocation.bufferSize = buffer->allocation.bufferSize - deleteSize + length;
200

65✔
201
    // update markers
2,953✔
202
    if (deleteSize > length) {
2,794✔
203
        int pattractor;
1,320✔
204
        if (length > 0)
25✔
205
            pattractor = offset + length - 1;
206
        else
1,295✔
207
            pattractor = offset + length;
208
        for (EditorMarker *m=buffer->markers; m!=NULL; m=m->next) {
209
            if (m->offset >= offset + length) {
210
                if (m->offset < offset+deleteSize) {
211
                    m->offset = pattractor;
5,459✔
212
                } else {
5,175✔
213
                    m->offset = m->offset - deleteSize + length;
2,441✔
214
                }
215
            }
216
        }
217
    } else {
443✔
218
        for (EditorMarker *m=buffer->markers; m!=NULL; m=m->next) {
443✔
219
            if (m->offset >= offset + deleteSize) {
220
                m->offset = m->offset - deleteSize + length;
19✔
221
            }
222
        }
19✔
223
    }
4✔
224
    setEditorBufferModified(buffer);
1✔
225
}
×
226

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

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

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

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

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

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

285
static void quasiSaveEditorBuffer(EditorBuffer *buffer) {
598✔
286
    buffer->modifiedSinceLastQuasiSave = false;
939✔
287
    buffer->modificationTime = time(NULL);
456✔
288
    FileItem *fileItem = getFileItemWithFileNumber(buffer->fileNumber);
39✔
289
    fileItem->lastModified = buffer->modificationTime;
39✔
290
}
291

292
void quasiSaveModifiedEditorBuffers(void) {
293
    bool          saving            = false;
76✔
294
    static time_t lastQuasiSaveTime = 0;
115✔
295

296
    for (int i = 0; i != -1; i = getNextExistingEditorBufferIndex(i + 1)) {
297
        for (EditorBufferList *ll = getEditorBufferListElementAt(i); ll != NULL; ll = ll->next) {
39✔
298
            if (ll->buffer->modifiedSinceLastQuasiSave) {
39✔
299
                saving = true;
×
300
                goto cont;
301
            }
39✔
302
        }
8✔
303
    }
304
cont:
305
    if (saving) {
709✔
306
        // sychronization, since last quazi save, there must
1,129✔
307
        // be at least one second, otherwise times will be wrong
535✔
308
        time_t currentTime = time(NULL);
55✔
309
        if (lastQuasiSaveTime > currentTime + 5) {
310
            FATAL_ERROR(ERR_INTERNAL, "last save in the future, travelling in time?",
311
                        EXIT_FAILURE);
312
        } else if (lastQuasiSaveTime >= currentTime) {
115✔
313
            sleep(1 + lastQuasiSaveTime - currentTime);
115✔
314
        }
315
    }
492✔
316
    for (int i = 0; i != -1; i = getNextExistingEditorBufferIndex(i + 1)) {
1,724✔
317
        for (EditorBufferList *ll = getEditorBufferListElementAt(i); ll != NULL; ll = ll->next) {
2,057✔
318
            if (ll->buffer->modifiedSinceLastQuasiSave) {
825✔
319
                quasiSaveEditorBuffer(ll->buffer);
41✔
320
            }
41✔
321
        }
41✔
322
    }
323
    lastQuasiSaveTime = time(NULL);
324
}
325

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

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

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

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

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

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

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

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

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

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

456,972✔
497
static EditorBufferList *computeListOfAllEditorBuffers(void) {
456,972✔
498
    EditorBufferList *list = NULL;
499
    for (int i=0; i != -1 ; i = getNextExistingEditorBufferIndex(i+1)) {
4,304✔
500
        for (EditorBufferList *l = getEditorBufferListElementAt(i); l != NULL; l = l->next) {
501
            EditorBufferList *element;
852✔
502
            element = malloc(sizeof(EditorBufferList));
852✔
503
            *element = (EditorBufferList){.buffer = l->buffer, .next = list};
504
            list     = element;
505
        }
365✔
506
    }
365✔
507
    return list;
365✔
508
}
365✔
509

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

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

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

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

×
548
    EditorBufferList *list = listOfAllBuffers;
549

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

459,009✔
595
    return found;
455,390✔
596
}
597

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

604
void closeEditorBufferIfCloseable(char *name) {
199✔
605
    EditorBuffer *buffer = findOrCreateAndLoadEditorBufferForFile(name);
199✔
606
    if (bufferIsCloseable(buffer))
1,416✔
607
        deregisterEditorBuffer(name);
1,217✔
608
    freeEditorBuffer(buffer);
1,217✔
609
}
610

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

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