1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * CodeCheck extension by Birgi Tamersoy
5 * birgitamersoy@gmail.com
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 * See README.txt for an overview of the Vim source code.
13 * code_check.c: On-the-fly syntax checking tool.
17 #include <semaphore.h>
20 #define CC_VERSION 0.1
49 CC_PROJECT
/* Makefile exists */
53 * Multiple buffers can be syntax checked simultaneously and each buffer
54 * has its own list of errors and warnings. Consequently we have two list
55 * structures. One holds information about processed buffers and the other
56 * one holds information about buffer-specific errors & warnings.
58 * Both lists will be accessed frequently, so they will be sorted:
59 * buffer list will be sorted with respect to full file names, and
60 * error/warning list will be sorted with respect to line numbers.
63 #define MAX_EW_TEXT 200
65 /* compile command length */
66 #define MAX_CMD_LENGTH 600
68 #define MAX_PATH_LENGTH 300
70 typedef struct cc_ewline_S cc_ewline_T
;
75 char_u ew_text
[MAX_EW_TEXT
];
79 typedef struct cc_bufline_S cc_bufline_T
;
84 cc_ewline_T
*buf_ewlist_head
;
85 pthread_mutex_t buf_mutex
;
86 char_u buf_compile_cmd
[MAX_CMD_LENGTH
];
89 typedef struct cc_info_S cc_info_T
;
92 cc_bufline_T
*cc_list_head
;
93 cc_bufline_T
*cc_list_curr
;
96 /* global list of buffers. */
97 static cc_info_T cc_list
;
98 #define MAX_BUFLINES 100
99 static cc_bufline_T
*cc_bufline_ptrs
[MAX_BUFLINES
];
101 /* supported languages, the format should be ".<ext1>" ... */
102 /* each extension should padded with ' ' characters, st. total is 5 chars */
103 static char_u
*cc_sup_exts
= (char_u
*) ".c "
107 static pthread_t cc_slave
;
109 /* a queue for the pending jobs that the worker thread should handle.
110 * basically a list of buffer compile requests. */
115 typedef struct cc_pjob_S cc_pjob_T
;
121 #define MAX_PENDING_JOBS 10
122 static cc_pjob_T
*cc_pjobs
[MAX_PENDING_JOBS
];
123 static int pindex
= 0;
124 static int cindex
= 0;
128 static pthread_mutex_t mutex
= PTHREAD_MUTEX_INITIALIZER
;
131 static void cc_free_ewlist(cc_ewline_T
*ewlist_head
);
132 static cc_bufline_T
*cc_locate_buf(buf_T
*buf
);
133 static cc_bufline_T
*cc_locate_buf_bin(buf_T
*buf
, int *buf_idx
,
134 int *put_before
, int mode
);
135 static void cc_free_buflist(cc_info_T
*cc_list_a
,
136 cc_bufline_T
*cc_bufline_ptrs_a
[MAX_BUFLINES
]);
137 static int cc_start_slave_thread(void);
138 static void *cc_slave_sroutine(void *args
);
139 static int cc_pjobs_produce(cc_pjob_T
*tmp_pjob
);
140 static cc_pjob_T
*cc_pjobs_consume(void);
141 static int cc_pjobs_buf_exists(cc_pjob_T
*tmp_pjob
);
142 static int cc_create_tmp_copy(buf_T
*buf
, char_u
*tmp_copy_ffname
,
144 static int cc_compile_tmp_copy(cc_bufline_T
*bufline
,
145 char_u
*tmp_copy_ffname
, int copy_type
);
146 static cc_ewline_T
*cc_create_ewlist(char_u
*tmp_out_ffname
);
147 void cc_sigalrm_handler(int signum
);
148 void cc_update_screen(void);
149 static void cc_free(void);
150 static cc_bufline_T
* cc_add_buf(buf_T
*buf
);
151 static int cc_set_tmp_copy_ffname(buf_T
*buf
, char_u
*tmp_copy_ffname
);
153 static int cc_started
= FALSE
;
154 static int old_p_ut
= 0;
159 * 2. error/warning format should be added so that new languages are
160 * easily added to the code_check.c.
164 * Initializes the related structures.
171 cc_list
.cc_bufcount
= 0;
172 cc_list
.cc_list_head
= NULL
;
173 cc_list
.cc_list_curr
= NULL
;
175 retval
= sem_init(&full
, 0, 0);
179 retval
= sem_init(&empty
, 0, MAX_PENDING_JOBS
);
183 cc_start_slave_thread();
185 for (i
= 0; i
< MAX_BUFLINES
; ++i
)
186 cc_bufline_ptrs
[i
] = NULL
;
188 for (i
= 0; i
< MAX_PENDING_JOBS
; ++i
)
200 * Returns the current number of buffers in the watchlist.
203 cc_get_bufcount(void) {
204 return cc_list
.cc_bufcount
;
208 * Returns TRUE if CodeCheck is already started.
211 cc_get_is_started(void) {
216 * CodeCheck creates a working thread which would run in the background.
217 * This thread is responsible of compiling the specified buffers, parsing
218 * the outputs and forming the corresponding error/warning lists.
221 cc_start_slave_thread(void) {
222 pthread_attr_t
*attr
= NULL
;
225 attr
= (pthread_attr_t
*) calloc(1, sizeof(pthread_attr_t
));
227 retval
= pthread_attr_init(attr
);
231 retval
= pthread_attr_setdetachstate(attr
, PTHREAD_CREATE_DETACHED
);
235 retval
= pthread_create(&cc_slave
, attr
, cc_slave_sroutine
, NULL
);
247 * Function updates the error/warning line numbers after new lines are inserted
248 * or some existing lines are removed. This is just to move the highlighted
249 * parts before an actual compile.
251 * TODO: This function is mainly copied from color_me.c (the preliminary
252 * project). So, double check if everything is OK or not!!!
255 cc_update_ew_lnums(buf_T
*buf
, int lnum
, int col
, long xtra
) {
259 cc_bufline_T
*tmp_bufline
;
260 cc_ewline_T
*tmp_ewline
;
266 tmp_bufline
= cc_locate_buf_bin(buf
, &dummy
, &dummy
, CC_FOR_FIND
);
267 if (tmp_bufline
== NULL
)
270 pthread_mutex_lock(&(tmp_bufline
->buf_mutex
));
272 for (tmp_ewline
= tmp_bufline
->buf_ewlist_head
;
273 tmp_ewline
!= NULL
; tmp_ewline
= tmp_ewline
->next
) {
276 if (tmp_ewline
->ew_lnum
< lnum
)
278 if (tmp_ewline
->ew_lnum
== lnum
) {
279 /* is this the beginning of the line? */
280 line
= ml_get_buf(buf
, lnum
, FALSE
);
281 for (i
= col
- 1; i
> 0 &&
282 (line
[i
] == '\t' || line
[i
] == ' '); --i
)
287 tmp_ewline
->ew_lnum
+= xtra
;
290 pthread_mutex_unlock(&(tmp_bufline
->buf_mutex
));
295 * Worker thread function, which continuously checks for unserved requests.
298 cc_slave_sroutine(void *args
) {
300 cc_bufline_T
*tmp_bufline
;
303 char_u tmp_copy_ffname
[MAX_PATH_LENGTH
];
304 char_u tmp_out_ffname
[MAX_CMD_LENGTH
];
305 cc_ewline_T
*ew_head
= NULL
;
308 /* consume a pending job */
309 tmp_pjob
= cc_pjobs_consume();
310 if (tmp_pjob
== NULL
)
313 /* when gui mode is used, an other update screen is required. */
314 /* i don't know why :)!!!. */
320 /* find the buffer line */
322 /* create the temporary copy */
323 retval
= cc_create_tmp_copy(tmp_pjob
->cc_pjob_buf
,
324 tmp_copy_ffname
, CC_STANDALONE
);
325 if (retval
== CC_FAIL
)
328 tmp_bufline
= cc_locate_buf_bin(tmp_pjob
->cc_pjob_buf
, &dummy
,
329 &dummy
, CC_FOR_FIND
);
330 if (tmp_bufline
== NULL
)
333 /* compile the temporary copy */
334 retval
= cc_compile_tmp_copy(tmp_bufline
, tmp_copy_ffname
,
336 if (retval
== CC_FAIL
)
339 /* create the error list from the temporary copy */
340 sprintf((char *)tmp_out_ffname
, "%s.out", (char *)tmp_copy_ffname
);
341 ew_head
= cc_create_ewlist(tmp_out_ffname
);
343 /* having ew_head == NULL is not an error, since all
344 * the errors and the warnings may be cleaned. */
346 /* free the previous list & set the new list */
347 pthread_mutex_lock(&(tmp_bufline
->buf_mutex
));
349 cc_free_ewlist(tmp_bufline
->buf_ewlist_head
);
350 tmp_bufline
->buf_ewlist_head
= ew_head
;
352 pthread_mutex_unlock(&(tmp_bufline
->buf_mutex
));
354 /* update the screen */
357 /* that would be it for this buffer */
362 * Function is used to update the screen properly.
365 cc_update_screen(void) {
369 /* in console mode updating the screen from the worker thread
370 * does not cause any problems. */
373 update_screen(SOME_VALID
);
379 /* updating the screen in gui mode is troublesome. */
384 bytes
[2] = KE_REDRAW
;
386 add_to_input_buf(bytes
, 3);
392 * Function returns the correct error/warning type for a specific lnum.
393 * Returns CC_NOEW if the lnum does not have an error or a warning.
396 cc_get_ew_type(buf_T
*buf
, linenr_T lnum
) {
400 cc_bufline_T
*tmp_bufline
;
401 cc_ewline_T
*tmp_ewline
;
403 int ew_type
= CC_NOEW
;
405 tmp_bufline
= cc_locate_buf_bin(buf
, &dummy
, &dummy
, CC_FOR_FIND
);
406 if (tmp_bufline
== NULL
)
409 pthread_mutex_lock(&(tmp_bufline
->buf_mutex
));
410 tmp_ewline
= tmp_bufline
->buf_ewlist_head
;
411 while (tmp_ewline
!= NULL
) {
412 if (tmp_ewline
->ew_lnum
!= lnum
) {
413 tmp_ewline
= tmp_ewline
->next
;
417 if (ew_type
< tmp_ewline
->ew_type
)
418 ew_type
= tmp_ewline
->ew_type
;
420 tmp_ewline
= tmp_ewline
->next
;
422 pthread_mutex_unlock(&(tmp_bufline
->buf_mutex
));
427 * Function creates a quickfix error list from the compiler output.
428 * TODO: Right now works only for .c files and the gcc compiler.
429 * Should be automated to work with multiple languages and multiple
433 cc_create_ewlist(char_u
*tmp_out_ffname
) {
434 FILE *err_file
= NULL
;
438 cc_ewline_T
*ew_head
= NULL
;
439 cc_ewline_T
*ew_curr
= NULL
;
440 char_u
*token1
= NULL
;
441 char_u
*token2
= NULL
;
442 char_u
*token3
= NULL
;
443 char_u
*token4
= NULL
;
444 cc_ewline_T
*tmp_ewline
= NULL
;
447 err_file
= fopen((char *)tmp_out_ffname
, "r");
448 if (err_file
== NULL
)
451 while ((read
= getline((char **) &buf
, &len
, err_file
)) != -1) {
452 token1
= (char_u
*)strtok((char *) buf
, ":");
453 token2
= (char_u
*)strtok(NULL
, ":");
454 token3
= (char_u
*)strtok(NULL
, ":");
455 token4
= (char_u
*)strtok(NULL
, ":");
457 /* TODO: be sure it is gXX type of output. */
462 tmp_ewline
= (cc_ewline_T
*) calloc(1, sizeof(cc_ewline_T
));
463 STRCPY(tmp_ewline
->ew_text
, token4
);
464 /* remove the last '\n' from the error/warning message */
465 tmp_ewline
->ew_text
[STRLEN(tmp_ewline
->ew_text
) - 1] = '\0';
466 tmp_ewline
->ew_lnum
= (linenr_T
) atoi((char *) token2
);
467 tmp_ewline
->ew_type
= token3
[1] == 'w' ? CC_WARNING
: CC_ERROR
;
470 ew_head
= tmp_ewline
;
471 ew_curr
= tmp_ewline
;
473 ew_curr
->next
= tmp_ewline
;
474 tmp_ewline
->prev
= ew_curr
;
475 ew_curr
= ew_curr
->next
;
479 /* buf should be freed, because it is allocated in getline */
487 * Function compiles the temporary copy saving the output in a
491 cc_compile_tmp_copy(cc_bufline_T
*bufline
, char_u
*tmp_copy_ffname
,
493 char_u cmd
[MAX_CMD_LENGTH
];
496 if (bufline
->buf_compile_cmd
[0] == NUL
)
499 /* clear the arrays. */
500 memset(cmd
, 0, MAX_CMD_LENGTH
);
502 /* direct STDOUT & STDERR to the same file, so that the output of
503 * this will not interfer with the vim terminal */
504 sprintf((char *)cmd
, "%s > %s.out 2>&1",
505 (char *)bufline
->buf_compile_cmd
, (char *)tmp_copy_ffname
);
507 retval
= system((char *)cmd
);
516 * Function creates a temporary copy of the buffer. copy_type determines
517 * the type of the copy process.
520 cc_create_tmp_copy(buf_T
*buf
, char_u
*tmp_copy_ffname
, int copy_type
) {
522 char_u cmd
[MAX_CMD_LENGTH
];
526 cc_set_tmp_copy_ffname(buf
, tmp_copy_ffname
);
527 sprintf((char *)cmd
, "touch %s", (char *)tmp_copy_ffname
);
529 retval
= system((char *)cmd
);
533 retval
= buf_write(buf
, tmp_copy_ffname
, NULL
,
534 (linenr_T
) 1, buf
->b_ml
.ml_line_count
, NULL
,
535 FALSE
, FALSE
, FALSE
, TRUE
);
543 /* these are not implemented yet. */
552 * Outside accessible compile request for a specific buffer.
555 cc_request_compile(buf_T
*buf
) {
561 tmp_pjob
= (cc_pjob_T
*) calloc(1, sizeof(cc_pjob_T
));
562 if (tmp_pjob
== NULL
)
565 tmp_pjob
->cc_pjob_buf
= buf
;
566 tmp_pjob
->cc_pjob_type
= CC_COMPILE
;
568 return cc_pjobs_produce(tmp_pjob
);
572 * Function required to populate the pending jobs array.
573 * TODO: FAILURE IN pthread_mutex_unlock is SERIOUS!!!
576 cc_pjobs_produce(cc_pjob_T
*tmp_pjob
) {
581 retval
= pthread_mutex_lock(&mutex
);
585 /* check if this buffer already has a pending job request. */
586 /* if so directly return. */
587 if (cc_pjobs_buf_exists(tmp_pjob
)) {
589 retval
= pthread_mutex_unlock(&mutex
);
595 cc_pjobs
[pindex
% MAX_PENDING_JOBS
] = tmp_pjob
;
598 retval
= pthread_mutex_unlock(&mutex
);
602 retval
= sem_post(&full
);
610 * Returns TRUE if there is another pending job for this process.
613 cc_pjobs_buf_exists(cc_pjob_T
*tmp_pjob
) {
616 for (i
= 0; i
< MAX_PENDING_JOBS
; ++i
) {
617 if (cc_pjobs
[i
] == NULL
||
618 strcmp((char *) cc_pjobs
[i
]->cc_pjob_buf
->b_ffname
,
619 (char *) tmp_pjob
->cc_pjob_buf
->b_ffname
))
628 * Removes the "top" element.
631 cc_pjobs_consume(void) {
633 cc_pjob_T
*tmp_pjob
= NULL
;
635 tmp_pjob
= (cc_pjob_T
*) calloc(1, sizeof(cc_pjob_T
));
636 if (tmp_pjob
== NULL
)
641 retval
= pthread_mutex_lock(&mutex
);
645 tmp_pjob
->cc_pjob_type
= cc_pjobs
[cindex
% MAX_PENDING_JOBS
]->cc_pjob_type
;
646 tmp_pjob
->cc_pjob_buf
= cc_pjobs
[cindex
% MAX_PENDING_JOBS
]->cc_pjob_buf
;
648 /* free the old job!!! */
649 free(cc_pjobs
[cindex
% MAX_PENDING_JOBS
]);
650 cc_pjobs
[cindex
% MAX_PENDING_JOBS
] = NULL
;
654 retval
= pthread_mutex_unlock(&mutex
);
658 retval
= sem_post(&empty
);
670 * Checks if the specified buffer can be syntax checked or not.
673 cc_is_buf_ok(buf_T
*buf
) {
677 char_u
*ffname
= NULL
;
681 if (buf
== NULL
|| ((ffname
= buf
->b_ffname
) == NULL
))
684 /* find the file extension */
685 p
= (char_u
*) strrchr((char *) ffname
, '.');
690 /* check if this extension is supported or not */
691 r
= (char_u
*) strstr((char *) cc_sup_exts
, (char *) p
);
700 * Returns TRUE if the specified buffer is in the watchlist.
701 * TODO: THIS CAN RETURN THE FOUND BUFFER TO SAVE SOME TIME.
705 cc_is_buf_watched(buf_T
*buf
) {
709 cc_bufline_T
*tmp_bufline
;
712 tmp_bufline
= cc_locate_buf_bin(buf
, &dummy
, &dummy
, CC_FOR_FIND
);
713 if (tmp_bufline
== NULL
)
720 * Finds and sets a file name for the temporary copy of the buffer.
723 cc_set_tmp_copy_ffname(buf_T
*buf
, char_u
*tmp_copy_ffname
) {
725 char_u tmp_buf
[MAX_PATH_LENGTH
];
728 /* clear the array. */
729 memset(tmp_buf
, 0, MAX_PATH_LENGTH
);
731 /* find the tmp_copy_ffname. */
732 /* uses gettail(buf->b_sfname) because sometimes b_sfname is
733 * actually b_ffname. */
734 buf_sfname
= buf
->b_sfname
? gettail(buf
->b_sfname
)
735 : gettail(buf
->b_ffname
);
736 if (buf_sfname
== NULL
|| !strcmp((char *) buf_sfname
, ""))
739 /* finds the folder path of the buffer. */
740 p
= (char_u
*)strstr((char *)buf
->b_ffname
, (char *)buf_sfname
);
743 STRNCPY(tmp_buf
, buf
->b_ffname
, (p
- buf
->b_ffname
));
745 /* rather than creating the copy in /tmp/, create it in the directory
746 * of the buffer. this solves a few issues without a lot of effort. */
747 sprintf((char *) tmp_copy_ffname
, "%s.cc_%s",
748 (char *) tmp_buf
, (char *) buf_sfname
);
753 * Adds the specified buffer and sets the compile command.
756 cc_addbuf_setcmd(buf_T
*buf
, char_u
*cmd
) {
757 cc_bufline_T
*tmp_bufline
= NULL
;
758 char_u tmp_compile_cmd
[MAX_CMD_LENGTH
];
760 char_u tmp_copy_ffname
[MAX_PATH_LENGTH
];
763 /* clear the arrays. */
764 memset(tmp_compile_cmd
, 0, MAX_CMD_LENGTH
);
765 memset(tmp_copy_ffname
, 0, MAX_PATH_LENGTH
);
767 tmp_bufline
= cc_add_buf(buf
);
768 if (tmp_bufline
== NULL
)
771 cc_set_tmp_copy_ffname(buf
, tmp_copy_ffname
);
773 /* at this point we should update the compile command, so
774 * that it works for the temporary copy, rather than the
776 * *** assumes that the user entered compile command has the
777 * full file name of the current buffer. */
778 p
= (char_u
*)strstr((char *)cmd
,
779 (char *)tmp_bufline
->buf_name
);
782 bname_len
= STRLEN(tmp_bufline
->buf_name
);
784 STRNCPY(tmp_compile_cmd
, cmd
,
786 STRCAT(tmp_compile_cmd
, tmp_copy_ffname
);
787 STRCAT(tmp_compile_cmd
, p
+ bname_len
);
789 STRCPY(tmp_bufline
->buf_compile_cmd
, tmp_compile_cmd
);
791 /* TODO: check if tmp_bufline->buf_compile_cmd is valid. */
796 * Adds the specified buffer to the watch list.
798 * modified a little: returns a pointer to the inserted cc_bufline_T
799 * object, to make things a little faster.
803 cc_add_buf(buf_T
*buf
) {
807 cc_bufline_T
*tmp_bufline
= NULL
;
808 cc_bufline_T
*tmp_insafter
= NULL
;
814 /* check if this buffer is in the watch list, if so don't add */
815 tmp_bufline
= cc_locate_buf_bin(buf
, &buf_idx
, &put_before
, CC_FOR_FIND
);
816 if (tmp_bufline
!= NULL
)
819 if (cc_list
.cc_bufcount
== MAX_BUFLINES
)
822 tmp_bufline
= (cc_bufline_T
*) calloc(1, sizeof(cc_bufline_T
));
824 if (tmp_bufline
== NULL
)
827 tmp_bufline
->buf_name
= buf
->b_ffname
;
828 memset(tmp_bufline
->buf_compile_cmd
, 0, MAX_CMD_LENGTH
);
829 pthread_mutex_init(&(tmp_bufline
->buf_mutex
), NULL
);
831 if (cc_list
.cc_bufcount
== 0) {
832 /* this is the first buffer */
833 cc_list
.cc_list_head
= tmp_bufline
;
834 tmp_bufline
->prev
= NULL
;
835 tmp_bufline
->next
= NULL
;
836 cc_bufline_ptrs
[0] = tmp_bufline
;
838 tmp_insafter
= cc_locate_buf_bin(buf
, &buf_idx
, &put_before
, CC_FOR_ADD
);
840 if (tmp_insafter
== NULL
) {
846 /* move elements in cc_bufline_ptrs */
847 for (i
= cc_list
.cc_bufcount
; i
> buf_idx
; --i
)
848 cc_bufline_ptrs
[i
] = cc_bufline_ptrs
[i
- 1];
850 cc_bufline_ptrs
[buf_idx
] = tmp_bufline
;
852 tmp_bufline
->prev
= tmp_insafter
->prev
;
853 if (tmp_insafter
->prev
!= NULL
)
854 tmp_insafter
->prev
->next
= tmp_bufline
;
856 cc_list
.cc_list_head
= tmp_bufline
;
858 tmp_bufline
->next
= tmp_insafter
;
859 tmp_insafter
->prev
= tmp_bufline
;
861 /* move elements in cc_bufline_ptrs */
862 for (i
= cc_list
.cc_bufcount
; i
> buf_idx
+ 1; --i
)
863 cc_bufline_ptrs
[i
] = cc_bufline_ptrs
[i
- 1];
865 cc_bufline_ptrs
[buf_idx
+ 1] = tmp_bufline
;
867 tmp_bufline
->next
= tmp_insafter
->next
;
868 if (tmp_bufline
->next
!= NULL
)
869 tmp_bufline
->next
->prev
= tmp_bufline
;
871 tmp_insafter
->next
= tmp_bufline
;
872 tmp_bufline
->prev
= tmp_insafter
;
876 /* create an initial compile request for this buffer */
877 retval
= cc_request_compile(buf
);
878 if (retval
== CC_FAIL
)
881 cc_list
.cc_list_curr
= tmp_bufline
;
882 cc_list
.cc_bufcount
++;
888 * Removes the specified buffer from the watch list.
889 * TODO: current implementation does not have sorted lists.
892 cc_rem_buf(buf_T
*buf
) {
896 cc_bufline_T
*tmp_bufline
= NULL
;
901 tmp_bufline
= cc_locate_buf_bin(buf
, &buf_idx
, &put_before
, CC_FOR_REM
);
903 if (tmp_bufline
== NULL
)
906 if (tmp_bufline
->prev
!= NULL
)
907 tmp_bufline
->prev
->next
= tmp_bufline
->next
;
909 if (tmp_bufline
->next
!= NULL
)
910 tmp_bufline
->next
->prev
= tmp_bufline
->prev
;
912 if (tmp_bufline
->buf_ewlist_head
!= NULL
)
913 cc_free_ewlist(tmp_bufline
->buf_ewlist_head
);
915 vim_free(tmp_bufline
);
917 /* update cc_bufline_ptrs */
918 for (i
= buf_idx
; i
< cc_list
.cc_bufcount
; ++i
)
919 cc_bufline_ptrs
[i
] = cc_bufline_ptrs
[i
+ 1];
921 cc_list
.cc_bufcount
--;
923 /* update the screen in case there are some highlighted lines. */
930 * Returns a pointer to the specified buffer node.
931 * Returns NULL if there is no such buffer.
932 * This is the linear search version.
933 * THIS SHOULD NOT BE USED ANYMORE!!!
935 static cc_bufline_T
*
936 cc_locate_buf(buf_T
*buf
) {
937 cc_bufline_T
*tmp_bufline
= NULL
;
938 char_u
*ffname
= NULL
;
940 ffname
= buf
->b_ffname
;
942 for (tmp_bufline
= cc_list
.cc_list_head
;
943 tmp_bufline
!= NULL
; tmp_bufline
= tmp_bufline
->next
) {
944 if (strcmp((char *) tmp_bufline
->buf_name
, (char *) ffname
))
954 * Binary search of the buffer list. Has two modes:
955 * - search for addition (find the correct position in the list which the
956 * specified buffer should be inserted to)(return CC_BUFEXISTS if the
957 * buffer is already in the watch list),
958 * - search for removal (find the exact location of the buffer, return NULL
959 * if could not be found).
961 static cc_bufline_T
*
962 cc_locate_buf_bin(buf_T
*buf
, int *buf_idx
, int *put_before
, int mode
) {
963 cc_bufline_T
*tmp_bufline
= NULL
;
965 int end
= cc_list
.cc_bufcount
- 1;
966 int mid
= (start
+ end
) / 2;
969 while (start
<= end
) {
970 mid
= (start
+ end
) / 2;
972 /* since this is a linked list we are using cc_bufline_ptrs
973 * to find the correct node. */
974 tmp_bufline
= cc_bufline_ptrs
[mid
];
976 retval
= strcmp((char *) buf
->b_ffname
, (char *) tmp_bufline
->buf_name
);
980 if (mode
== CC_FOR_ADD
)
982 else if (mode
== CC_FOR_REM
|| mode
== CC_FOR_FIND
)
984 } else if (retval
< 0) {
993 /* the buffer is not inside the list */
995 if (mode
== CC_FOR_ADD
)
997 else if (mode
== CC_FOR_REM
|| mode
== CC_FOR_FIND
)
999 else /* should not be reached. */
1004 * Frees the specified error & warning list.
1007 cc_free_ewlist(cc_ewline_T
*ewlist_head
) {
1008 if (ewlist_head
== NULL
)
1011 cc_ewline_T
*tmp_ewline
= ewlist_head
;
1012 cc_ewline_T
*tmp_ewlinep
= ewlist_head
;
1014 while (tmp_ewline
!= NULL
) {
1015 tmp_ewline
= tmp_ewline
->next
;
1017 tmp_ewlinep
= tmp_ewline
;
1022 * Frees the specified buffer watch list.
1023 * TODO: CHECK THIS BEHAVIOR!!! IMPORTANT!!!
1026 cc_free_buflist(cc_info_T
*cc_list_a
,
1027 cc_bufline_T
*cc_bufline_ptrs_a
[MAX_BUFLINES
]) {
1030 if (cc_list_a
->cc_list_head
== NULL
)
1033 cc_bufline_T
*tmp_bufline
= cc_list_a
->cc_list_head
;
1034 cc_bufline_T
*tmp_buflinep
= cc_list_a
->cc_list_head
;
1036 while (tmp_bufline
!= NULL
) {
1037 cc_free_ewlist(tmp_bufline
->buf_ewlist_head
);
1039 tmp_bufline
= tmp_bufline
->next
;
1041 tmp_buflinep
= tmp_bufline
;
1044 for (i
= 0; i
< cc_list_a
->cc_bufcount
; ++i
)
1045 cc_bufline_ptrs_a
[i
] = NULL
;
1047 cc_list_a
->cc_list_head
= NULL
;
1048 cc_list_a
->cc_list_curr
= NULL
;
1049 cc_list_a
->cc_bufcount
= 0;
1060 cc_list
.cc_list_curr
= NULL
;
1061 cc_free_buflist(&cc_list
, cc_bufline_ptrs
);
1065 * TODO: cc_exit() function.
1066 * what else should it do???