Comment detail

lessの実装 (Nested Flatten)
効率はともかく、巨大なファイルでも表示できるように作ってみました。 表示はcurses、ファイルの行インデックススキャンをバックグラウンドで行うためにpthreadを使用しています。 行インデックスもテンポラリファイルとして書き出しているので、fpos_tが32bitの環境でも2GB、64bitなら8EBまでいける(自信なし)はずです。 ただし、システム側に懲りすぎたので、タブやら一行の折り返しやらは手を抜いて全く手付かずです。 検索機能もUIが手抜きのためインクリメンタルサーチしかできません。
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/*
    Large less
        programed by M.Suzuki
        ver 0.1     2008/8/4

    key binding
        n,j,^n      scroll up
        p,k,^p      scroll down
        /           i-search
        ESC         i-search cancel
        TAB         next search(i-search only)
        q           quit
 */

#include <stdio.h>
#include <string.h>
#include <curses.h>
#include <pthread.h>

#define LINE_MAX    256     /* file text width max  */

#define False   0
#define True    (!False)

static pthread_mutex_t file_mutex;
static FILE* fileFp;
static FILE* seekFp;
static fpos_t lineTop;
static fpos_t lineMax;
static bool readMaxFlag;
static bool abortFlag;

static void ScanWait()
{
    pthread_mutex_lock(&file_mutex);
    while( lineTop + LINES >= lineMax ){
        static struct timespec time10ms = {0,10*1000*1000};
        pthread_mutex_unlock(&file_mutex);
        nanosleep(&time10ms,NULL);
        pthread_mutex_lock(&file_mutex);
        if( readMaxFlag ){
            break;
        }
    }   /* end of while */
    pthread_mutex_unlock(&file_mutex);
}

static char* ReadLine(int y, char* buff)
{
    char* text = NULL;

    ScanWait();
    pthread_mutex_lock(&file_mutex);
    if( lineTop + y + 1 < lineMax ){
        fpos_t offset = sizeof(fpos_t)*(lineTop+y);

        fsetpos(seekFp,&offset);
        fread(&offset,sizeof(fpos_t),1,seekFp);
        fsetpos(fileFp,&offset);
        if( fgets(buff,LINE_MAX,fileFp) ){
            text = buff;
        }
    }
    pthread_mutex_unlock(&file_mutex);
    return text;
}

static void DrawLine(int y)
{
    char* text;
    char buff[LINE_MAX+1];

    text = ReadLine(y,buff);
    if( text == NULL ){
        text = "~";
    }
    mvinsstr(y,0,text);
}

static void ViewAll()
{
    int y;

    erase();
    for(y=0;y<LINES;y++){
        DrawLine(y);
    }
}

static void RollUp()
{
    ScanWait();
    pthread_mutex_lock(&file_mutex);
    if( lineTop >= lineMax ){
        if( readMaxFlag ){
            pthread_mutex_unlock(&file_mutex);
            return;
        }
    }
    lineTop++;
    pthread_mutex_unlock(&file_mutex);
    move(0,0);
    deleteln();
    move(LINES-1,0);
    DrawLine(LINES-1);
    refresh();
}

static void RollDown()
{
    pthread_mutex_lock(&file_mutex);
    if( lineTop <= 0 ){
        pthread_mutex_unlock(&file_mutex);
        return;
    }
    lineTop--;
    pthread_mutex_unlock(&file_mutex);
    move(0,0);
    insdelln(1);
    DrawLine(0);
    refresh();
}

static void Search()
{
    char search[LINE_MAX];
    int len = 0;

    while(1){
        int key = getch();
        int y = 0;
        if( key == 0x1b ){
            break;
        }
        if( key == '\t' ){
            y = 1;
        } else {
            if( len < LINE_MAX ){
                search[len++] = key;
                search[len] = '\0';
            }
        }
        while(1){
            char buff[LINE_MAX+1];
            if( ReadLine(y,buff) == NULL ){
                return;
            }
            if( strstr(buff,search) ){
                pthread_mutex_lock(&file_mutex);
                lineTop += y;
                pthread_mutex_unlock(&file_mutex);
                ViewAll();
                break;
            }
            y++;
        }   /* end of while */
    }   /* end of while */
}

static void KeyLoop()
{
    ViewAll();
    while(1){
        int key = getch();
        if( key == 'q' ){
            break;
        }
        switch(key){
          case 'N'-'@':
          case 'n':
          case 'j':
            RollUp();
            break;
          case 'P'-'@':
          case 'p':
          case 'k':
            RollDown();
            break;
          case '/':
            Search();
            break;
        }   /* end of switch */
    }   /* end of while */
}

void* ScanThread(void* arg)
{
    fpos_t filePos;

    fgetpos(fileFp, &filePos);
    while(1){
        char buff[LINE_MAX+1];
        fpos_t fpos = sizeof(fpos_t)*lineMax;

        pthread_mutex_lock(&file_mutex);
        fsetpos(seekFp,&fpos);
        fwrite(&filePos,sizeof(fpos_t),1,seekFp);
        lineMax++;
        fsetpos(fileFp,&filePos);
        if( fgets(buff,LINE_MAX,fileFp) == NULL ){
            break;
        }
        fgetpos(fileFp,&filePos);
        if( abortFlag ){
            break;
        }
        pthread_mutex_unlock(&file_mutex);
    }   /* end of while */
    readMaxFlag = True;
    pthread_mutex_unlock(&file_mutex);
    return NULL;
}

static void MainLoop()
{
    pthread_t scanThread_id;
    char tmpName[L_tmpnam];

    tmpnam(tmpName);
    if( (seekFp=fopen(tmpName,"w+b")) == NULL ){
        perror(tmpName);
        return;
    }

    pthread_mutex_init(&file_mutex,NULL);

    lineTop = 0;
    lineMax = 0;
    if( pthread_create(&scanThread_id,NULL,ScanThread,NULL)!=0){
        perror("ScanThread");
        return;
    }

    initscr();
    noecho();
    raw();
    cbreak();

    KeyLoop();

    nocbreak();
    noraw();
    echo();
    endwin();

    pthread_mutex_lock(&file_mutex);
    abortFlag = True;
    pthread_mutex_unlock(&file_mutex);
    pthread_join(scanThread_id,NULL);

    fclose(seekFp);
    remove(tmpName);
}

int main(int argc, char* argv[])
{
    char* fname = NULL;
    int i;

    for(i=1;i<argc;i++){
        char* p = argv[i];
        if( *p == '-' ){
            /* option   */
        } else {
            fname = argv[i];
        }
    }   /* end of for */
    if( fname != NULL ){
        if( (fileFp=fopen(fname,"r")) == NULL ){
            perror(fname);
            return 1;
        }
        MainLoop();
        fclose(fileFp);
    }
    return 0;
}

Index

Feed

Other

Link

Pathtraq

loading...