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

thoni56 / c-xrefactory / 1645

11 Dec 2025 02:53PM UTC coverage: 82.617% (+0.02%) from 82.595%
1645

push

travis-ci

thoni56
[fix] Add missing `referenceableItem.h` to repo

13175 of 15947 relevant lines covered (82.62%)

17985717.33 hits per line

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

81.49
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) {
146✔
40
    initEditorBufferTable();
146✔
41
}
146✔
42

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

46
    buffer = getEditorBufferForFile(path);
1,011,018✔
47
    if (buffer != NULL)
1,011,018✔
48
        return buffer->modificationTime;
1,006,874✔
49
    return fileModificationTime(path);
4,144✔
50
}
51

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

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

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

64
    buffer = getEditorBufferForFile(path);
1,022,649✔
65
    if (buffer != NULL)
1,022,649✔
66
        return true;
1,007,010✔
67
    return fileExists(path);
15,639✔
68
}
69

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

74
void freeTextSpace(char *space, int index) {
458,463✔
75
    EditorMemoryBlock *sp;
76
    sp = (EditorMemoryBlock *) space;
458,463✔
77
    sp->next = editorMemory[index];
458,463✔
78
    editorMemory[index] = sp;
458,463✔
79
}
458,463✔
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) {
458,825✔
87
    allocateNewEditorBufferTextSpace(buffer, fileSize);
458,825✔
88

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

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

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

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

103
    int size = bufferSize;
104
    int n;
917,644✔
105
    do {
917,644✔
106
        n    = readFile(file, text, 1, size);
917,644✔
107
        text = text + n;
917,644✔
108
        size = size - n;
458,825✔
109
    } while (n>0);
110
    closeFile(file);
458,825✔
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
        }
458,825✔
120
    }
458,825✔
121
    performEncodingAdjustments(buffer);
458,825✔
122
    buffer->modificationTime = modificationTime;
458,825✔
123
    buffer->size = fileSize;
458,825✔
124
    buffer->textLoaded = true;
125
}
126

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

1,190,872✔
133
    // Ensure size to allocate is at least
732,039✔
134
    for(; allocatedSize<minSize; ) {
732,039✔
135
        allocIndex++;
136
        allocatedSize = allocatedSize << 1;
137
    }
458,833✔
138

458,833✔
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,379✔
146
    } else {
147
        editorMemory[allocIndex] = editorMemory[allocIndex]->next;
458,833✔
148
    }
149
    buffer->allocation = (EditorBufferAllocationData){.bufferSize = size, .text = space+EDITOR_FREE_PREFIX_SIZE,
150
                                           .allocatedFreePrefixSize = EDITOR_FREE_PREFIX_SIZE,
151
                                           .allocatedBlock = space, .allocatedIndex = allocIndex,
458,833✔
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
    }
381✔
317
    for (int i = 0; i != -1; i = getNextExistingEditorBufferIndex(i + 1)) {
1,418✔
318
        for (EditorBufferList *ll = getEditorBufferListElementAt(i); ll != NULL; ll = ll->next) {
1,772✔
319
            if (ll->buffer->modifiedSinceLastQuasiSave) {
735✔
320
                quasiSaveEditorBuffer(ll->buffer);
9✔
321
            }
9✔
322
        }
9✔
323
    }
324
    lastQuasiSaveTime = time(NULL);
325
}
326

327
void loadAllOpenedEditorBuffers(void) {
381✔
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;
2✔
411
                    reference    = reference->next;
412
                    while (reference != NULL && !isVisibleUsage(reference->usage))
413
                        reference = reference->next;
2✔
414
                }
2✔
415
            }
3✔
416
        }
1✔
417
    }
1✔
418
    // get markers in the same order as were references
1✔
419
    // ?? is this still needed?
1✔
420
    LIST_REVERSE(EditorMarkerList, markerList);
1✔
421
    return markerList;
1✔
422
}
825✔
423

825✔
424
Reference *convertEditorMarkersToReferences(EditorMarkerList **editorMarkerListP) {
1✔
425

1✔
426
    LIST_MERGE_SORT(EditorMarkerList, *editorMarkerListP, editorMarkerListBefore);
427

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

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

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

454,989✔
494
static EditorBufferList *computeListOfAllEditorBuffers(void) {
454,989✔
495
    EditorBufferList *list = NULL;
496
    for (int i=0; i != -1 ; i = getNextExistingEditorBufferIndex(i+1)) {
4,147✔
497
        for (EditorBufferList *l = getEditorBufferListElementAt(i); l != NULL; l = l->next) {
498
            EditorBufferList *element;
237✔
499
            element = malloc(sizeof(EditorBufferList));
237✔
500
            *element = (EditorBufferList){.buffer = l->buffer, .next = list};
501
            list     = element;
502
        }
114✔
503
    }
114✔
504
    return list;
114✔
505
}
114✔
506

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

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

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

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

×
545
    EditorBufferList *list = listOfAllBuffers;
546

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

457,299✔
592
    return found;
453,712✔
593
}
594

453,710✔
595
static bool bufferIsCloseable(EditorBuffer *buffer) {
453,710✔
596
    return buffer != NULL && buffer->textLoaded && buffer->markers==NULL
597
        && buffer->preLoadedFromFile == NULL  /* not -preloaded */
598
        && ! buffer->modified;
3,587✔
599
}
3,587✔
600

601
void closeEditorBufferIfCloseable(char *name) {
140✔
602
    EditorBuffer *buffer = findOrCreateAndLoadEditorBufferForFile(name);
140✔
603
    if (bufferIsCloseable(buffer))
1,303✔
604
        deregisterEditorBuffer(name);
1,163✔
605
    freeEditorBuffer(buffer);
1,163✔
606
}
607

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

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