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 :)!!!. */
318 /* find the buffer line */
320 /* create the temporary copy */
321 retval
= cc_create_tmp_copy(tmp_pjob
->cc_pjob_buf
,
322 tmp_copy_ffname
, CC_STANDALONE
);
323 if (retval
== CC_FAIL
)
326 tmp_bufline
= cc_locate_buf_bin(tmp_pjob
->cc_pjob_buf
, &dummy
,
327 &dummy
, CC_FOR_FIND
);
328 if (tmp_bufline
== NULL
)
331 /* compile the temporary copy */
332 retval
= cc_compile_tmp_copy(tmp_bufline
, tmp_copy_ffname
,
334 if (retval
== CC_FAIL
)
337 /* create the error list from the temporary copy */
338 sprintf((char *)tmp_out_ffname
, "%s.out", (char *)tmp_copy_ffname
);
339 ew_head
= cc_create_ewlist(tmp_out_ffname
);
341 /* having ew_head == NULL is not an error, since all
342 * the errors and the warnings may be cleaned. */
344 /* free the previous list & set the new list */
345 pthread_mutex_lock(&(tmp_bufline
->buf_mutex
));
347 cc_free_ewlist(tmp_bufline
->buf_ewlist_head
);
348 tmp_bufline
->buf_ewlist_head
= ew_head
;
350 pthread_mutex_unlock(&(tmp_bufline
->buf_mutex
));
352 /* update the screen */
355 /* that would be it for this buffer */
360 * Function is used to update the screen properly.
363 cc_update_screen(void) {
365 /* in console mode updating the screen from the worker thread
366 * does not cause any problems. */
369 update_screen(SOME_VALID
);
374 /* updating the screen in gui mode is troublesome. */
379 bytes
[2] = KE_REDRAW
;
381 add_to_input_buf(bytes
, 3);
386 * Function returns the correct error/warning type for a specific lnum.
387 * Returns CC_NOEW if the lnum does not have an error or a warning.
390 cc_get_ew_type(buf_T
*buf
, linenr_T lnum
) {
394 cc_bufline_T
*tmp_bufline
;
395 cc_ewline_T
*tmp_ewline
;
397 int ew_type
= CC_NOEW
;
399 tmp_bufline
= cc_locate_buf_bin(buf
, &dummy
, &dummy
, CC_FOR_FIND
);
400 if (tmp_bufline
== NULL
)
403 pthread_mutex_lock(&(tmp_bufline
->buf_mutex
));
404 tmp_ewline
= tmp_bufline
->buf_ewlist_head
;
405 while (tmp_ewline
!= NULL
) {
406 if (tmp_ewline
->ew_lnum
!= lnum
) {
407 tmp_ewline
= tmp_ewline
->next
;
411 if (ew_type
< tmp_ewline
->ew_type
)
412 ew_type
= tmp_ewline
->ew_type
;
414 tmp_ewline
= tmp_ewline
->next
;
416 pthread_mutex_unlock(&(tmp_bufline
->buf_mutex
));
421 * Function creates a quickfix error list from the compiler output.
422 * TODO: Right now works only for .c files and the gcc compiler.
423 * Should be automated to work with multiple languages and multiple
427 cc_create_ewlist(char_u
*tmp_out_ffname
) {
428 FILE *err_file
= NULL
;
432 cc_ewline_T
*ew_head
= NULL
;
433 cc_ewline_T
*ew_curr
= NULL
;
434 char_u
*token1
= NULL
;
435 char_u
*token2
= NULL
;
436 char_u
*token3
= NULL
;
437 char_u
*token4
= NULL
;
438 cc_ewline_T
*tmp_ewline
= NULL
;
441 err_file
= fopen((char *)tmp_out_ffname
, "r");
442 if (err_file
== NULL
)
445 while ((read
= getline((char **) &buf
, &len
, err_file
)) != -1) {
446 token1
= (char_u
*)strtok((char *) buf
, ":");
447 token2
= (char_u
*)strtok(NULL
, ":");
448 token3
= (char_u
*)strtok(NULL
, ":");
449 token4
= (char_u
*)strtok(NULL
, ":");
451 /* TODO: be sure it is gXX type of output. */
456 tmp_ewline
= (cc_ewline_T
*) calloc(1, sizeof(cc_ewline_T
));
457 STRCPY(tmp_ewline
->ew_text
, token4
);
458 /* remove the last '\n' from the error/warning message */
459 tmp_ewline
->ew_text
[STRLEN(tmp_ewline
->ew_text
) - 1] = '\0';
460 tmp_ewline
->ew_lnum
= (linenr_T
) atoi((char *) token2
);
461 tmp_ewline
->ew_type
= token3
[1] == 'w' ? CC_WARNING
: CC_ERROR
;
464 ew_head
= tmp_ewline
;
465 ew_curr
= tmp_ewline
;
467 ew_curr
->next
= tmp_ewline
;
468 tmp_ewline
->prev
= ew_curr
;
469 ew_curr
= ew_curr
->next
;
473 /* buf should be freed, because it is allocated in getline */
481 * Function compiles the temporary copy saving the output in a
485 cc_compile_tmp_copy(cc_bufline_T
*bufline
, char_u
*tmp_copy_ffname
,
487 char_u cmd
[MAX_CMD_LENGTH
];
489 if (bufline
->buf_compile_cmd
[0] == NUL
)
492 /* clear the arrays. */
493 memset(cmd
, 0, MAX_CMD_LENGTH
);
495 /* direct STDOUT & STDERR to the same file, so that the output of
496 * this will not interfer with the vim terminal */
497 sprintf((char *)cmd
, "%s > %s.out 2>&1",
498 (char *)bufline
->buf_compile_cmd
, (char *)tmp_copy_ffname
);
507 * Function creates a temporary copy of the buffer. copy_type determines
508 * the type of the copy process.
511 cc_create_tmp_copy(buf_T
*buf
, char_u
*tmp_copy_ffname
, int copy_type
) {
513 char_u cmd
[MAX_CMD_LENGTH
];
517 cc_set_tmp_copy_ffname(buf
, tmp_copy_ffname
);
518 sprintf((char *)cmd
, "touch %s", (char *)tmp_copy_ffname
);
522 retval
= buf_write(buf
, tmp_copy_ffname
, NULL
,
523 (linenr_T
) 1, buf
->b_ml
.ml_line_count
, NULL
,
524 FALSE
, FALSE
, FALSE
, TRUE
);
532 /* these are not implemented yet. */
541 * Outside accessible compile request for a specific buffer.
544 cc_request_compile(buf_T
*buf
) {
550 tmp_pjob
= (cc_pjob_T
*) calloc(1, sizeof(cc_pjob_T
));
551 if (tmp_pjob
== NULL
)
554 tmp_pjob
->cc_pjob_buf
= buf
;
555 tmp_pjob
->cc_pjob_type
= CC_COMPILE
;
557 return cc_pjobs_produce(tmp_pjob
);
561 * Function required to populate the pending jobs array.
562 * TODO: FAILURE IN pthread_mutex_unlock is SERIOUS!!!
565 cc_pjobs_produce(cc_pjob_T
*tmp_pjob
) {
570 retval
= pthread_mutex_lock(&mutex
);
574 /* check if this buffer already has a pending job request. */
575 /* if so directly return. */
576 if (cc_pjobs_buf_exists(tmp_pjob
)) {
578 retval
= pthread_mutex_unlock(&mutex
);
584 cc_pjobs
[pindex
% MAX_PENDING_JOBS
] = tmp_pjob
;
587 retval
= pthread_mutex_unlock(&mutex
);
591 retval
= sem_post(&full
);
599 * Returns TRUE if there is another pending job for this process.
602 cc_pjobs_buf_exists(cc_pjob_T
*tmp_pjob
) {
605 for (i
= 0; i
< MAX_PENDING_JOBS
; ++i
) {
606 if (cc_pjobs
[i
] == NULL
||
607 strcmp((char *) cc_pjobs
[i
]->cc_pjob_buf
->b_ffname
,
608 (char *) tmp_pjob
->cc_pjob_buf
->b_ffname
))
617 * Removes the "top" element.
620 cc_pjobs_consume(void) {
622 cc_pjob_T
*tmp_pjob
= NULL
;
624 tmp_pjob
= (cc_pjob_T
*) calloc(1, sizeof(cc_pjob_T
));
625 if (tmp_pjob
== NULL
)
630 retval
= pthread_mutex_lock(&mutex
);
634 tmp_pjob
->cc_pjob_type
= cc_pjobs
[cindex
% MAX_PENDING_JOBS
]->cc_pjob_type
;
635 tmp_pjob
->cc_pjob_buf
= cc_pjobs
[cindex
% MAX_PENDING_JOBS
]->cc_pjob_buf
;
637 /* free the old job!!! */
638 free(cc_pjobs
[cindex
% MAX_PENDING_JOBS
]);
639 cc_pjobs
[cindex
% MAX_PENDING_JOBS
] = NULL
;
643 retval
= pthread_mutex_unlock(&mutex
);
647 retval
= sem_post(&empty
);
659 * Checks if the specified buffer can be syntax checked or not.
662 cc_is_buf_ok(buf_T
*buf
) {
666 char_u
*ffname
= NULL
;
670 if (buf
== NULL
|| ((ffname
= buf
->b_ffname
) == NULL
))
673 /* find the file extension */
674 p
= (char_u
*) strrchr((char *) ffname
, '.');
679 /* check if this extension is supported or not */
680 r
= (char_u
*) strstr((char *) cc_sup_exts
, (char *) p
);
689 * Returns TRUE if the specified buffer is in the watchlist.
690 * TODO: THIS CAN RETURN THE FOUND BUFFER TO SAVE SOME TIME.
694 cc_is_buf_watched(buf_T
*buf
) {
698 cc_bufline_T
*tmp_bufline
;
701 tmp_bufline
= cc_locate_buf_bin(buf
, &dummy
, &dummy
, CC_FOR_FIND
);
702 if (tmp_bufline
== NULL
)
709 * Finds and sets a file name for the temporary copy of the buffer.
712 cc_set_tmp_copy_ffname(buf_T
*buf
, char_u
*tmp_copy_ffname
) {
714 char_u tmp_buf
[MAX_PATH_LENGTH
];
717 /* clear the array. */
718 memset(tmp_buf
, 0, MAX_PATH_LENGTH
);
720 /* find the tmp_copy_ffname. */
721 /* uses gettail(buf->b_sfname) because sometimes b_sfname is
722 * actually b_ffname. */
723 buf_sfname
= buf
->b_sfname
? gettail(buf
->b_sfname
)
724 : gettail(buf
->b_ffname
);
725 if (buf_sfname
== NULL
|| !strcmp((char *) buf_sfname
, ""))
728 /* finds the folder path of the buffer. */
729 p
= (char_u
*)strstr((char *)buf
->b_ffname
, (char *)buf_sfname
);
732 STRNCPY(tmp_buf
, buf
->b_ffname
, (p
- buf
->b_ffname
));
734 /* rather than creating the copy in /tmp/, create it in the directory
735 * of the buffer. this solves a few issues without a lot of effort. */
736 sprintf((char *) tmp_copy_ffname
, "%s.cc_%s",
737 (char *) tmp_buf
, (char *) buf_sfname
);
742 * Adds the specified buffer and sets the compile command.
745 cc_addbuf_setcmd(buf_T
*buf
, char_u
*cmd
) {
746 cc_bufline_T
*tmp_bufline
= NULL
;
747 char_u tmp_compile_cmd
[MAX_CMD_LENGTH
];
749 char_u tmp_copy_ffname
[MAX_PATH_LENGTH
];
752 /* clear the arrays. */
753 memset(tmp_compile_cmd
, 0, MAX_CMD_LENGTH
);
754 memset(tmp_copy_ffname
, 0, MAX_PATH_LENGTH
);
756 tmp_bufline
= cc_add_buf(buf
);
757 if (tmp_bufline
== NULL
)
760 cc_set_tmp_copy_ffname(buf
, tmp_copy_ffname
);
762 /* at this point we should update the compile command, so
763 * that it works for the temporary copy, rather than the
765 * *** assumes that the user entered compile command has the
766 * full file name of the current buffer. */
767 p
= (char_u
*)strstr((char *)cmd
,
768 (char *)tmp_bufline
->buf_name
);
771 bname_len
= STRLEN(tmp_bufline
->buf_name
);
773 STRNCPY(tmp_compile_cmd
, cmd
,
775 STRCAT(tmp_compile_cmd
, tmp_copy_ffname
);
776 STRCAT(tmp_compile_cmd
, p
+ bname_len
);
778 STRCPY(tmp_bufline
->buf_compile_cmd
, tmp_compile_cmd
);
780 /* TODO: check if tmp_bufline->buf_compile_cmd is valid. */
785 * Adds the specified buffer to the watch list.
787 * modified a little: returns a pointer to the inserted cc_bufline_T
788 * object, to make things a little faster.
792 cc_add_buf(buf_T
*buf
) {
796 cc_bufline_T
*tmp_bufline
= NULL
;
797 cc_bufline_T
*tmp_insafter
= NULL
;
803 /* check if this buffer is in the watch list, if so don't add */
804 tmp_bufline
= cc_locate_buf_bin(buf
, &buf_idx
, &put_before
, CC_FOR_FIND
);
805 if (tmp_bufline
!= NULL
)
808 if (cc_list
.cc_bufcount
== MAX_BUFLINES
)
811 tmp_bufline
= (cc_bufline_T
*) calloc(1, sizeof(cc_bufline_T
));
813 if (tmp_bufline
== NULL
)
816 tmp_bufline
->buf_name
= buf
->b_ffname
;
817 memset(tmp_bufline
->buf_compile_cmd
, 0, MAX_CMD_LENGTH
);
818 pthread_mutex_init(&(tmp_bufline
->buf_mutex
), NULL
);
820 if (cc_list
.cc_bufcount
== 0) {
821 /* this is the first buffer */
822 cc_list
.cc_list_head
= tmp_bufline
;
823 tmp_bufline
->prev
= NULL
;
824 tmp_bufline
->next
= NULL
;
825 cc_bufline_ptrs
[0] = tmp_bufline
;
827 tmp_insafter
= cc_locate_buf_bin(buf
, &buf_idx
, &put_before
, CC_FOR_ADD
);
829 if (tmp_insafter
== NULL
) {
835 /* move elements in cc_bufline_ptrs */
836 for (i
= cc_list
.cc_bufcount
; i
> buf_idx
; --i
)
837 cc_bufline_ptrs
[i
] = cc_bufline_ptrs
[i
- 1];
839 cc_bufline_ptrs
[buf_idx
] = tmp_bufline
;
841 tmp_bufline
->prev
= tmp_insafter
->prev
;
842 if (tmp_insafter
->prev
!= NULL
)
843 tmp_insafter
->prev
->next
= tmp_bufline
;
845 cc_list
.cc_list_head
= tmp_bufline
;
847 tmp_bufline
->next
= tmp_insafter
;
848 tmp_insafter
->prev
= tmp_bufline
;
850 /* move elements in cc_bufline_ptrs */
851 for (i
= cc_list
.cc_bufcount
; i
> buf_idx
+ 1; --i
)
852 cc_bufline_ptrs
[i
] = cc_bufline_ptrs
[i
- 1];
854 cc_bufline_ptrs
[buf_idx
+ 1] = tmp_bufline
;
856 tmp_bufline
->next
= tmp_insafter
->next
;
857 if (tmp_bufline
->next
!= NULL
)
858 tmp_bufline
->next
->prev
= tmp_bufline
;
860 tmp_insafter
->next
= tmp_bufline
;
861 tmp_bufline
->prev
= tmp_insafter
;
865 /* create an initial compile request for this buffer */
866 retval
= cc_request_compile(buf
);
867 if (retval
== CC_FAIL
)
870 cc_list
.cc_list_curr
= tmp_bufline
;
871 cc_list
.cc_bufcount
++;
877 * Removes the specified buffer from the watch list.
878 * TODO: current implementation does not have sorted lists.
881 cc_rem_buf(buf_T
*buf
) {
885 cc_bufline_T
*tmp_bufline
= NULL
;
890 tmp_bufline
= cc_locate_buf_bin(buf
, &buf_idx
, &put_before
, CC_FOR_REM
);
892 if (tmp_bufline
== NULL
)
895 if (tmp_bufline
->prev
!= NULL
)
896 tmp_bufline
->prev
->next
= tmp_bufline
->next
;
898 if (tmp_bufline
->next
!= NULL
)
899 tmp_bufline
->next
->prev
= tmp_bufline
->prev
;
901 if (tmp_bufline
->buf_ewlist_head
!= NULL
)
902 cc_free_ewlist(tmp_bufline
->buf_ewlist_head
);
904 vim_free(tmp_bufline
);
906 /* update cc_bufline_ptrs */
907 for (i
= buf_idx
; i
< cc_list
.cc_bufcount
; ++i
)
908 cc_bufline_ptrs
[i
] = cc_bufline_ptrs
[i
+ 1];
910 cc_list
.cc_bufcount
--;
912 /* update the screen in case there are some highlighted lines. */
919 * Returns a pointer to the specified buffer node.
920 * Returns NULL if there is no such buffer.
921 * This is the linear search version.
922 * THIS SHOULD NOT BE USED ANYMORE!!!
924 static cc_bufline_T
*
925 cc_locate_buf(buf_T
*buf
) {
926 cc_bufline_T
*tmp_bufline
= NULL
;
927 char_u
*ffname
= NULL
;
929 ffname
= buf
->b_ffname
;
931 for (tmp_bufline
= cc_list
.cc_list_head
;
932 tmp_bufline
!= NULL
; tmp_bufline
= tmp_bufline
->next
) {
933 if (strcmp((char *) tmp_bufline
->buf_name
, (char *) ffname
))
943 * Binary search of the buffer list. Has two modes:
944 * - search for addition (find the correct position in the list which the
945 * specified buffer should be inserted to)(return CC_BUFEXISTS if the
946 * buffer is already in the watch list),
947 * - search for removal (find the exact location of the buffer, return NULL
948 * if could not be found).
950 static cc_bufline_T
*
951 cc_locate_buf_bin(buf_T
*buf
, int *buf_idx
, int *put_before
, int mode
) {
952 cc_bufline_T
*tmp_bufline
= NULL
;
954 int end
= cc_list
.cc_bufcount
- 1;
955 int mid
= (start
+ end
) / 2;
958 while (start
<= end
) {
959 mid
= (start
+ end
) / 2;
961 /* since this is a linked list we are using cc_bufline_ptrs
962 * to find the correct node. */
963 tmp_bufline
= cc_bufline_ptrs
[mid
];
965 retval
= strcmp((char *) buf
->b_ffname
, (char *) tmp_bufline
->buf_name
);
969 if (mode
== CC_FOR_ADD
)
971 else if (mode
== CC_FOR_REM
|| mode
== CC_FOR_FIND
)
973 } else if (retval
< 0) {
982 /* the buffer is not inside the list */
984 if (mode
== CC_FOR_ADD
)
986 else if (mode
== CC_FOR_REM
|| mode
== CC_FOR_FIND
)
988 else /* should not be reached. */
993 * Frees the specified error & warning list.
996 cc_free_ewlist(cc_ewline_T
*ewlist_head
) {
997 if (ewlist_head
== NULL
)
1000 cc_ewline_T
*tmp_ewline
= ewlist_head
;
1001 cc_ewline_T
*tmp_ewlinep
= ewlist_head
;
1003 while (tmp_ewline
!= NULL
) {
1004 tmp_ewline
= tmp_ewline
->next
;
1006 tmp_ewlinep
= tmp_ewline
;
1011 * Frees the specified buffer watch list.
1012 * TODO: CHECK THIS BEHAVIOR!!! IMPORTANT!!!
1015 cc_free_buflist(cc_info_T
*cc_list_a
,
1016 cc_bufline_T
*cc_bufline_ptrs_a
[MAX_BUFLINES
]) {
1019 if (cc_list_a
->cc_list_head
== NULL
)
1022 cc_bufline_T
*tmp_bufline
= cc_list_a
->cc_list_head
;
1023 cc_bufline_T
*tmp_buflinep
= cc_list_a
->cc_list_head
;
1025 while (tmp_bufline
!= NULL
) {
1026 cc_free_ewlist(tmp_bufline
->buf_ewlist_head
);
1028 tmp_bufline
= tmp_bufline
->next
;
1030 tmp_buflinep
= tmp_bufline
;
1033 for (i
= 0; i
< cc_list_a
->cc_bufcount
; ++i
)
1034 cc_bufline_ptrs_a
[i
] = NULL
;
1036 cc_list_a
->cc_list_head
= NULL
;
1037 cc_list_a
->cc_list_curr
= NULL
;
1038 cc_list_a
->cc_bufcount
= 0;
1049 cc_list
.cc_list_curr
= NULL
;
1050 cc_free_buflist(&cc_list
, cc_bufline_ptrs
);
1054 * TODO: cc_exit() function.
1055 * what else should it do???