Mercurial > vim
comparison src/evalfunc.c @ 17530:ef23ec1eee54 v8.1.1763
patch 8.1.1763: evalfunc.c is still too big
commit https://github.com/vim/vim/commit/9f9fe37f6750f342255a51f158a7bb372c827f7f
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Jul 27 23:12:12 2019 +0200
patch 8.1.1763: evalfunc.c is still too big
Problem: Evalfunc.c is still too big.
Solution: Move dict and list functions to a better place.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 27 Jul 2019 23:15:05 +0200 |
parents | bfc5a2962f38 |
children | 2b4c138bf8e9 |
comparison
equal
deleted
inserted
replaced
17529:4bd2e3339ba3 | 17530:ef23ec1eee54 |
---|---|
178 static void f_getwinvar(typval_T *argvars, typval_T *rettv); | 178 static void f_getwinvar(typval_T *argvars, typval_T *rettv); |
179 static void f_glob(typval_T *argvars, typval_T *rettv); | 179 static void f_glob(typval_T *argvars, typval_T *rettv); |
180 static void f_globpath(typval_T *argvars, typval_T *rettv); | 180 static void f_globpath(typval_T *argvars, typval_T *rettv); |
181 static void f_glob2regpat(typval_T *argvars, typval_T *rettv); | 181 static void f_glob2regpat(typval_T *argvars, typval_T *rettv); |
182 static void f_has(typval_T *argvars, typval_T *rettv); | 182 static void f_has(typval_T *argvars, typval_T *rettv); |
183 static void f_has_key(typval_T *argvars, typval_T *rettv); | |
184 static void f_haslocaldir(typval_T *argvars, typval_T *rettv); | 183 static void f_haslocaldir(typval_T *argvars, typval_T *rettv); |
185 static void f_hasmapto(typval_T *argvars, typval_T *rettv); | 184 static void f_hasmapto(typval_T *argvars, typval_T *rettv); |
186 static void f_histadd(typval_T *argvars, typval_T *rettv); | 185 static void f_histadd(typval_T *argvars, typval_T *rettv); |
187 static void f_histdel(typval_T *argvars, typval_T *rettv); | 186 static void f_histdel(typval_T *argvars, typval_T *rettv); |
188 static void f_histget(typval_T *argvars, typval_T *rettv); | 187 static void f_histget(typval_T *argvars, typval_T *rettv); |
205 static void f_islocked(typval_T *argvars, typval_T *rettv); | 204 static void f_islocked(typval_T *argvars, typval_T *rettv); |
206 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) | 205 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) |
207 static void f_isinf(typval_T *argvars, typval_T *rettv); | 206 static void f_isinf(typval_T *argvars, typval_T *rettv); |
208 static void f_isnan(typval_T *argvars, typval_T *rettv); | 207 static void f_isnan(typval_T *argvars, typval_T *rettv); |
209 #endif | 208 #endif |
210 static void f_items(typval_T *argvars, typval_T *rettv); | |
211 static void f_join(typval_T *argvars, typval_T *rettv); | |
212 static void f_keys(typval_T *argvars, typval_T *rettv); | |
213 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv); | 209 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv); |
214 static void f_len(typval_T *argvars, typval_T *rettv); | 210 static void f_len(typval_T *argvars, typval_T *rettv); |
215 static void f_libcall(typval_T *argvars, typval_T *rettv); | 211 static void f_libcall(typval_T *argvars, typval_T *rettv); |
216 static void f_libcallnr(typval_T *argvars, typval_T *rettv); | 212 static void f_libcallnr(typval_T *argvars, typval_T *rettv); |
217 static void f_line(typval_T *argvars, typval_T *rettv); | 213 static void f_line(typval_T *argvars, typval_T *rettv); |
218 static void f_line2byte(typval_T *argvars, typval_T *rettv); | 214 static void f_line2byte(typval_T *argvars, typval_T *rettv); |
219 static void f_lispindent(typval_T *argvars, typval_T *rettv); | 215 static void f_lispindent(typval_T *argvars, typval_T *rettv); |
220 static void f_list2str(typval_T *argvars, typval_T *rettv); | |
221 static void f_localtime(typval_T *argvars, typval_T *rettv); | 216 static void f_localtime(typval_T *argvars, typval_T *rettv); |
222 #ifdef FEAT_FLOAT | 217 #ifdef FEAT_FLOAT |
223 static void f_log(typval_T *argvars, typval_T *rettv); | 218 static void f_log(typval_T *argvars, typval_T *rettv); |
224 static void f_log10(typval_T *argvars, typval_T *rettv); | 219 static void f_log10(typval_T *argvars, typval_T *rettv); |
225 #endif | 220 #endif |
328 static void f_simplify(typval_T *argvars, typval_T *rettv); | 323 static void f_simplify(typval_T *argvars, typval_T *rettv); |
329 #ifdef FEAT_FLOAT | 324 #ifdef FEAT_FLOAT |
330 static void f_sin(typval_T *argvars, typval_T *rettv); | 325 static void f_sin(typval_T *argvars, typval_T *rettv); |
331 static void f_sinh(typval_T *argvars, typval_T *rettv); | 326 static void f_sinh(typval_T *argvars, typval_T *rettv); |
332 #endif | 327 #endif |
333 static void f_sort(typval_T *argvars, typval_T *rettv); | |
334 static void f_soundfold(typval_T *argvars, typval_T *rettv); | 328 static void f_soundfold(typval_T *argvars, typval_T *rettv); |
335 static void f_spellbadword(typval_T *argvars, typval_T *rettv); | 329 static void f_spellbadword(typval_T *argvars, typval_T *rettv); |
336 static void f_spellsuggest(typval_T *argvars, typval_T *rettv); | 330 static void f_spellsuggest(typval_T *argvars, typval_T *rettv); |
337 static void f_split(typval_T *argvars, typval_T *rettv); | 331 static void f_split(typval_T *argvars, typval_T *rettv); |
338 #ifdef FEAT_FLOAT | 332 #ifdef FEAT_FLOAT |
390 static void f_trunc(typval_T *argvars, typval_T *rettv); | 384 static void f_trunc(typval_T *argvars, typval_T *rettv); |
391 #endif | 385 #endif |
392 static void f_type(typval_T *argvars, typval_T *rettv); | 386 static void f_type(typval_T *argvars, typval_T *rettv); |
393 static void f_undofile(typval_T *argvars, typval_T *rettv); | 387 static void f_undofile(typval_T *argvars, typval_T *rettv); |
394 static void f_undotree(typval_T *argvars, typval_T *rettv); | 388 static void f_undotree(typval_T *argvars, typval_T *rettv); |
395 static void f_uniq(typval_T *argvars, typval_T *rettv); | |
396 static void f_values(typval_T *argvars, typval_T *rettv); | |
397 static void f_virtcol(typval_T *argvars, typval_T *rettv); | 389 static void f_virtcol(typval_T *argvars, typval_T *rettv); |
398 static void f_visualmode(typval_T *argvars, typval_T *rettv); | 390 static void f_visualmode(typval_T *argvars, typval_T *rettv); |
399 static void f_wildmenumode(typval_T *argvars, typval_T *rettv); | 391 static void f_wildmenumode(typval_T *argvars, typval_T *rettv); |
400 static void f_win_execute(typval_T *argvars, typval_T *rettv); | 392 static void f_win_execute(typval_T *argvars, typval_T *rettv); |
401 static void f_win_findbuf(typval_T *argvars, typval_T *rettv); | 393 static void f_win_findbuf(typval_T *argvars, typval_T *rettv); |
6579 | 6571 |
6580 rettv->vval.v_number = n; | 6572 rettv->vval.v_number = n; |
6581 } | 6573 } |
6582 | 6574 |
6583 /* | 6575 /* |
6584 * "has_key()" function | |
6585 */ | |
6586 static void | |
6587 f_has_key(typval_T *argvars, typval_T *rettv) | |
6588 { | |
6589 if (argvars[0].v_type != VAR_DICT) | |
6590 { | |
6591 emsg(_(e_dictreq)); | |
6592 return; | |
6593 } | |
6594 if (argvars[0].vval.v_dict == NULL) | |
6595 return; | |
6596 | |
6597 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict, | |
6598 tv_get_string(&argvars[1]), -1) != NULL; | |
6599 } | |
6600 | |
6601 /* | |
6602 * "haslocaldir()" function | 6576 * "haslocaldir()" function |
6603 */ | 6577 */ |
6604 static void | 6578 static void |
6605 f_haslocaldir(typval_T *argvars, typval_T *rettv) | 6579 f_haslocaldir(typval_T *argvars, typval_T *rettv) |
6606 { | 6580 { |
7239 && isnan(argvars[0].vval.v_float); | 7213 && isnan(argvars[0].vval.v_float); |
7240 } | 7214 } |
7241 #endif | 7215 #endif |
7242 | 7216 |
7243 /* | 7217 /* |
7244 * "items(dict)" function | |
7245 */ | |
7246 static void | |
7247 f_items(typval_T *argvars, typval_T *rettv) | |
7248 { | |
7249 dict_list(argvars, rettv, 2); | |
7250 } | |
7251 | |
7252 /* | |
7253 * "join()" function | |
7254 */ | |
7255 static void | |
7256 f_join(typval_T *argvars, typval_T *rettv) | |
7257 { | |
7258 garray_T ga; | |
7259 char_u *sep; | |
7260 | |
7261 if (argvars[0].v_type != VAR_LIST) | |
7262 { | |
7263 emsg(_(e_listreq)); | |
7264 return; | |
7265 } | |
7266 if (argvars[0].vval.v_list == NULL) | |
7267 return; | |
7268 if (argvars[1].v_type == VAR_UNKNOWN) | |
7269 sep = (char_u *)" "; | |
7270 else | |
7271 sep = tv_get_string_chk(&argvars[1]); | |
7272 | |
7273 rettv->v_type = VAR_STRING; | |
7274 | |
7275 if (sep != NULL) | |
7276 { | |
7277 ga_init2(&ga, (int)sizeof(char), 80); | |
7278 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0); | |
7279 ga_append(&ga, NUL); | |
7280 rettv->vval.v_string = (char_u *)ga.ga_data; | |
7281 } | |
7282 else | |
7283 rettv->vval.v_string = NULL; | |
7284 } | |
7285 | |
7286 /* | |
7287 * "keys()" function | |
7288 */ | |
7289 static void | |
7290 f_keys(typval_T *argvars, typval_T *rettv) | |
7291 { | |
7292 dict_list(argvars, rettv, 0); | |
7293 } | |
7294 | |
7295 /* | |
7296 * "last_buffer_nr()" function. | 7218 * "last_buffer_nr()" function. |
7297 */ | 7219 */ |
7298 static void | 7220 static void |
7299 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv) | 7221 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv) |
7300 { | 7222 { |
7455 curwin->w_cursor = pos; | 7377 curwin->w_cursor = pos; |
7456 } | 7378 } |
7457 else | 7379 else |
7458 #endif | 7380 #endif |
7459 rettv->vval.v_number = -1; | 7381 rettv->vval.v_number = -1; |
7460 } | |
7461 | |
7462 /* | |
7463 * "list2str()" function | |
7464 */ | |
7465 static void | |
7466 f_list2str(typval_T *argvars, typval_T *rettv) | |
7467 { | |
7468 list_T *l; | |
7469 listitem_T *li; | |
7470 garray_T ga; | |
7471 int utf8 = FALSE; | |
7472 | |
7473 rettv->v_type = VAR_STRING; | |
7474 rettv->vval.v_string = NULL; | |
7475 if (argvars[0].v_type != VAR_LIST) | |
7476 { | |
7477 emsg(_(e_invarg)); | |
7478 return; | |
7479 } | |
7480 | |
7481 l = argvars[0].vval.v_list; | |
7482 if (l == NULL) | |
7483 return; // empty list results in empty string | |
7484 | |
7485 if (argvars[1].v_type != VAR_UNKNOWN) | |
7486 utf8 = (int)tv_get_number_chk(&argvars[1], NULL); | |
7487 | |
7488 ga_init2(&ga, 1, 80); | |
7489 if (has_mbyte || utf8) | |
7490 { | |
7491 char_u buf[MB_MAXBYTES + 1]; | |
7492 int (*char2bytes)(int, char_u *); | |
7493 | |
7494 if (utf8 || enc_utf8) | |
7495 char2bytes = utf_char2bytes; | |
7496 else | |
7497 char2bytes = mb_char2bytes; | |
7498 | |
7499 for (li = l->lv_first; li != NULL; li = li->li_next) | |
7500 { | |
7501 buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL; | |
7502 ga_concat(&ga, buf); | |
7503 } | |
7504 ga_append(&ga, NUL); | |
7505 } | |
7506 else if (ga_grow(&ga, list_len(l) + 1) == OK) | |
7507 { | |
7508 for (li = l->lv_first; li != NULL; li = li->li_next) | |
7509 ga_append(&ga, tv_get_number(&li->li_tv)); | |
7510 ga_append(&ga, NUL); | |
7511 } | |
7512 | |
7513 rettv->v_type = VAR_STRING; | |
7514 rettv->vval.v_string = ga.ga_data; | |
7515 } | 7382 } |
7516 | 7383 |
7517 /* | 7384 /* |
7518 * "localtime()" function | 7385 * "localtime()" function |
7519 */ | 7386 */ |
9235 * "remove()" function | 9102 * "remove()" function |
9236 */ | 9103 */ |
9237 static void | 9104 static void |
9238 f_remove(typval_T *argvars, typval_T *rettv) | 9105 f_remove(typval_T *argvars, typval_T *rettv) |
9239 { | 9106 { |
9240 list_T *l; | |
9241 listitem_T *item, *item2; | |
9242 listitem_T *li; | |
9243 long idx; | |
9244 long end; | |
9245 char_u *key; | |
9246 dict_T *d; | |
9247 dictitem_T *di; | |
9248 char_u *arg_errmsg = (char_u *)N_("remove() argument"); | 9107 char_u *arg_errmsg = (char_u *)N_("remove() argument"); |
9249 int error = FALSE; | |
9250 | 9108 |
9251 if (argvars[0].v_type == VAR_DICT) | 9109 if (argvars[0].v_type == VAR_DICT) |
9252 { | 9110 dict_remove(argvars, rettv, arg_errmsg); |
9253 if (argvars[2].v_type != VAR_UNKNOWN) | |
9254 semsg(_(e_toomanyarg), "remove()"); | |
9255 else if ((d = argvars[0].vval.v_dict) != NULL | |
9256 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE)) | |
9257 { | |
9258 key = tv_get_string_chk(&argvars[1]); | |
9259 if (key != NULL) | |
9260 { | |
9261 di = dict_find(d, key, -1); | |
9262 if (di == NULL) | |
9263 semsg(_(e_dictkey), key); | |
9264 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE) | |
9265 && !var_check_ro(di->di_flags, arg_errmsg, TRUE)) | |
9266 { | |
9267 *rettv = di->di_tv; | |
9268 init_tv(&di->di_tv); | |
9269 dictitem_remove(d, di); | |
9270 } | |
9271 } | |
9272 } | |
9273 } | |
9274 else if (argvars[0].v_type == VAR_BLOB) | 9111 else if (argvars[0].v_type == VAR_BLOB) |
9275 { | 9112 blob_remove(argvars, rettv); |
9276 idx = (long)tv_get_number_chk(&argvars[1], &error); | 9113 else if (argvars[0].v_type == VAR_LIST) |
9277 if (!error) | 9114 list_remove(argvars, rettv, arg_errmsg); |
9278 { | 9115 else |
9279 blob_T *b = argvars[0].vval.v_blob; | |
9280 int len = blob_len(b); | |
9281 char_u *p; | |
9282 | |
9283 if (idx < 0) | |
9284 // count from the end | |
9285 idx = len + idx; | |
9286 if (idx < 0 || idx >= len) | |
9287 { | |
9288 semsg(_(e_blobidx), idx); | |
9289 return; | |
9290 } | |
9291 if (argvars[2].v_type == VAR_UNKNOWN) | |
9292 { | |
9293 // Remove one item, return its value. | |
9294 p = (char_u *)b->bv_ga.ga_data; | |
9295 rettv->vval.v_number = (varnumber_T) *(p + idx); | |
9296 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1); | |
9297 --b->bv_ga.ga_len; | |
9298 } | |
9299 else | |
9300 { | |
9301 blob_T *blob; | |
9302 | |
9303 // Remove range of items, return list with values. | |
9304 end = (long)tv_get_number_chk(&argvars[2], &error); | |
9305 if (error) | |
9306 return; | |
9307 if (end < 0) | |
9308 // count from the end | |
9309 end = len + end; | |
9310 if (end >= len || idx > end) | |
9311 { | |
9312 semsg(_(e_blobidx), end); | |
9313 return; | |
9314 } | |
9315 blob = blob_alloc(); | |
9316 if (blob == NULL) | |
9317 return; | |
9318 blob->bv_ga.ga_len = end - idx + 1; | |
9319 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL) | |
9320 { | |
9321 vim_free(blob); | |
9322 return; | |
9323 } | |
9324 p = (char_u *)b->bv_ga.ga_data; | |
9325 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx, | |
9326 (size_t)(end - idx + 1)); | |
9327 ++blob->bv_refcount; | |
9328 rettv->v_type = VAR_BLOB; | |
9329 rettv->vval.v_blob = blob; | |
9330 | |
9331 mch_memmove(p + idx, p + end + 1, (size_t)(len - end)); | |
9332 b->bv_ga.ga_len -= end - idx + 1; | |
9333 } | |
9334 } | |
9335 } | |
9336 else if (argvars[0].v_type != VAR_LIST) | |
9337 semsg(_(e_listdictblobarg), "remove()"); | 9116 semsg(_(e_listdictblobarg), "remove()"); |
9338 else if ((l = argvars[0].vval.v_list) != NULL | |
9339 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE)) | |
9340 { | |
9341 idx = (long)tv_get_number_chk(&argvars[1], &error); | |
9342 if (error) | |
9343 ; // type error: do nothing, errmsg already given | |
9344 else if ((item = list_find(l, idx)) == NULL) | |
9345 semsg(_(e_listidx), idx); | |
9346 else | |
9347 { | |
9348 if (argvars[2].v_type == VAR_UNKNOWN) | |
9349 { | |
9350 /* Remove one item, return its value. */ | |
9351 vimlist_remove(l, item, item); | |
9352 *rettv = item->li_tv; | |
9353 vim_free(item); | |
9354 } | |
9355 else | |
9356 { | |
9357 // Remove range of items, return list with values. | |
9358 end = (long)tv_get_number_chk(&argvars[2], &error); | |
9359 if (error) | |
9360 ; // type error: do nothing | |
9361 else if ((item2 = list_find(l, end)) == NULL) | |
9362 semsg(_(e_listidx), end); | |
9363 else | |
9364 { | |
9365 int cnt = 0; | |
9366 | |
9367 for (li = item; li != NULL; li = li->li_next) | |
9368 { | |
9369 ++cnt; | |
9370 if (li == item2) | |
9371 break; | |
9372 } | |
9373 if (li == NULL) /* didn't find "item2" after "item" */ | |
9374 emsg(_(e_invrange)); | |
9375 else | |
9376 { | |
9377 vimlist_remove(l, item, item2); | |
9378 if (rettv_list_alloc(rettv) == OK) | |
9379 { | |
9380 l = rettv->vval.v_list; | |
9381 l->lv_first = item; | |
9382 l->lv_last = item2; | |
9383 item->li_prev = NULL; | |
9384 item2->li_next = NULL; | |
9385 l->lv_len = cnt; | |
9386 } | |
9387 } | |
9388 } | |
9389 } | |
9390 } | |
9391 } | |
9392 } | 9117 } |
9393 | 9118 |
9394 /* | 9119 /* |
9395 * "rename({from}, {to})" function | 9120 * "rename({from}, {to})" function |
9396 */ | 9121 */ |
11098 else | 10823 else |
11099 rettv->vval.v_float = 0.0; | 10824 rettv->vval.v_float = 0.0; |
11100 } | 10825 } |
11101 #endif | 10826 #endif |
11102 | 10827 |
11103 static int item_compare(const void *s1, const void *s2); | |
11104 static int item_compare2(const void *s1, const void *s2); | |
11105 | |
11106 /* struct used in the array that's given to qsort() */ | |
11107 typedef struct | |
11108 { | |
11109 listitem_T *item; | |
11110 int idx; | |
11111 } sortItem_T; | |
11112 | |
11113 /* struct storing information about current sort */ | |
11114 typedef struct | |
11115 { | |
11116 int item_compare_ic; | |
11117 int item_compare_numeric; | |
11118 int item_compare_numbers; | |
11119 #ifdef FEAT_FLOAT | |
11120 int item_compare_float; | |
11121 #endif | |
11122 char_u *item_compare_func; | |
11123 partial_T *item_compare_partial; | |
11124 dict_T *item_compare_selfdict; | |
11125 int item_compare_func_err; | |
11126 int item_compare_keep_zero; | |
11127 } sortinfo_T; | |
11128 static sortinfo_T *sortinfo = NULL; | |
11129 #define ITEM_COMPARE_FAIL 999 | |
11130 | |
11131 /* | |
11132 * Compare functions for f_sort() and f_uniq() below. | |
11133 */ | |
11134 static int | |
11135 item_compare(const void *s1, const void *s2) | |
11136 { | |
11137 sortItem_T *si1, *si2; | |
11138 typval_T *tv1, *tv2; | |
11139 char_u *p1, *p2; | |
11140 char_u *tofree1 = NULL, *tofree2 = NULL; | |
11141 int res; | |
11142 char_u numbuf1[NUMBUFLEN]; | |
11143 char_u numbuf2[NUMBUFLEN]; | |
11144 | |
11145 si1 = (sortItem_T *)s1; | |
11146 si2 = (sortItem_T *)s2; | |
11147 tv1 = &si1->item->li_tv; | |
11148 tv2 = &si2->item->li_tv; | |
11149 | |
11150 if (sortinfo->item_compare_numbers) | |
11151 { | |
11152 varnumber_T v1 = tv_get_number(tv1); | |
11153 varnumber_T v2 = tv_get_number(tv2); | |
11154 | |
11155 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; | |
11156 } | |
11157 | |
11158 #ifdef FEAT_FLOAT | |
11159 if (sortinfo->item_compare_float) | |
11160 { | |
11161 float_T v1 = tv_get_float(tv1); | |
11162 float_T v2 = tv_get_float(tv2); | |
11163 | |
11164 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; | |
11165 } | |
11166 #endif | |
11167 | |
11168 /* tv2string() puts quotes around a string and allocates memory. Don't do | |
11169 * that for string variables. Use a single quote when comparing with a | |
11170 * non-string to do what the docs promise. */ | |
11171 if (tv1->v_type == VAR_STRING) | |
11172 { | |
11173 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) | |
11174 p1 = (char_u *)"'"; | |
11175 else | |
11176 p1 = tv1->vval.v_string; | |
11177 } | |
11178 else | |
11179 p1 = tv2string(tv1, &tofree1, numbuf1, 0); | |
11180 if (tv2->v_type == VAR_STRING) | |
11181 { | |
11182 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) | |
11183 p2 = (char_u *)"'"; | |
11184 else | |
11185 p2 = tv2->vval.v_string; | |
11186 } | |
11187 else | |
11188 p2 = tv2string(tv2, &tofree2, numbuf2, 0); | |
11189 if (p1 == NULL) | |
11190 p1 = (char_u *)""; | |
11191 if (p2 == NULL) | |
11192 p2 = (char_u *)""; | |
11193 if (!sortinfo->item_compare_numeric) | |
11194 { | |
11195 if (sortinfo->item_compare_ic) | |
11196 res = STRICMP(p1, p2); | |
11197 else | |
11198 res = STRCMP(p1, p2); | |
11199 } | |
11200 else | |
11201 { | |
11202 double n1, n2; | |
11203 n1 = strtod((char *)p1, (char **)&p1); | |
11204 n2 = strtod((char *)p2, (char **)&p2); | |
11205 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1; | |
11206 } | |
11207 | |
11208 /* When the result would be zero, compare the item indexes. Makes the | |
11209 * sort stable. */ | |
11210 if (res == 0 && !sortinfo->item_compare_keep_zero) | |
11211 res = si1->idx > si2->idx ? 1 : -1; | |
11212 | |
11213 vim_free(tofree1); | |
11214 vim_free(tofree2); | |
11215 return res; | |
11216 } | |
11217 | |
11218 static int | |
11219 item_compare2(const void *s1, const void *s2) | |
11220 { | |
11221 sortItem_T *si1, *si2; | |
11222 int res; | |
11223 typval_T rettv; | |
11224 typval_T argv[3]; | |
11225 int dummy; | |
11226 char_u *func_name; | |
11227 partial_T *partial = sortinfo->item_compare_partial; | |
11228 | |
11229 /* shortcut after failure in previous call; compare all items equal */ | |
11230 if (sortinfo->item_compare_func_err) | |
11231 return 0; | |
11232 | |
11233 si1 = (sortItem_T *)s1; | |
11234 si2 = (sortItem_T *)s2; | |
11235 | |
11236 if (partial == NULL) | |
11237 func_name = sortinfo->item_compare_func; | |
11238 else | |
11239 func_name = partial_name(partial); | |
11240 | |
11241 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED | |
11242 * in the copy without changing the original list items. */ | |
11243 copy_tv(&si1->item->li_tv, &argv[0]); | |
11244 copy_tv(&si2->item->li_tv, &argv[1]); | |
11245 | |
11246 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */ | |
11247 res = call_func(func_name, -1, &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, | |
11248 partial, sortinfo->item_compare_selfdict); | |
11249 clear_tv(&argv[0]); | |
11250 clear_tv(&argv[1]); | |
11251 | |
11252 if (res == FAIL) | |
11253 res = ITEM_COMPARE_FAIL; | |
11254 else | |
11255 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err); | |
11256 if (sortinfo->item_compare_func_err) | |
11257 res = ITEM_COMPARE_FAIL; /* return value has wrong type */ | |
11258 clear_tv(&rettv); | |
11259 | |
11260 /* When the result would be zero, compare the pointers themselves. Makes | |
11261 * the sort stable. */ | |
11262 if (res == 0 && !sortinfo->item_compare_keep_zero) | |
11263 res = si1->idx > si2->idx ? 1 : -1; | |
11264 | |
11265 return res; | |
11266 } | |
11267 | |
11268 /* | |
11269 * "sort({list})" function | |
11270 */ | |
11271 static void | |
11272 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) | |
11273 { | |
11274 list_T *l; | |
11275 listitem_T *li; | |
11276 sortItem_T *ptrs; | |
11277 sortinfo_T *old_sortinfo; | |
11278 sortinfo_T info; | |
11279 long len; | |
11280 long i; | |
11281 | |
11282 /* Pointer to current info struct used in compare function. Save and | |
11283 * restore the current one for nested calls. */ | |
11284 old_sortinfo = sortinfo; | |
11285 sortinfo = &info; | |
11286 | |
11287 if (argvars[0].v_type != VAR_LIST) | |
11288 semsg(_(e_listarg), sort ? "sort()" : "uniq()"); | |
11289 else | |
11290 { | |
11291 l = argvars[0].vval.v_list; | |
11292 if (l == NULL || var_check_lock(l->lv_lock, | |
11293 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), | |
11294 TRUE)) | |
11295 goto theend; | |
11296 rettv_list_set(rettv, l); | |
11297 | |
11298 len = list_len(l); | |
11299 if (len <= 1) | |
11300 goto theend; /* short list sorts pretty quickly */ | |
11301 | |
11302 info.item_compare_ic = FALSE; | |
11303 info.item_compare_numeric = FALSE; | |
11304 info.item_compare_numbers = FALSE; | |
11305 #ifdef FEAT_FLOAT | |
11306 info.item_compare_float = FALSE; | |
11307 #endif | |
11308 info.item_compare_func = NULL; | |
11309 info.item_compare_partial = NULL; | |
11310 info.item_compare_selfdict = NULL; | |
11311 if (argvars[1].v_type != VAR_UNKNOWN) | |
11312 { | |
11313 /* optional second argument: {func} */ | |
11314 if (argvars[1].v_type == VAR_FUNC) | |
11315 info.item_compare_func = argvars[1].vval.v_string; | |
11316 else if (argvars[1].v_type == VAR_PARTIAL) | |
11317 info.item_compare_partial = argvars[1].vval.v_partial; | |
11318 else | |
11319 { | |
11320 int error = FALSE; | |
11321 | |
11322 i = (long)tv_get_number_chk(&argvars[1], &error); | |
11323 if (error) | |
11324 goto theend; /* type error; errmsg already given */ | |
11325 if (i == 1) | |
11326 info.item_compare_ic = TRUE; | |
11327 else if (argvars[1].v_type != VAR_NUMBER) | |
11328 info.item_compare_func = tv_get_string(&argvars[1]); | |
11329 else if (i != 0) | |
11330 { | |
11331 emsg(_(e_invarg)); | |
11332 goto theend; | |
11333 } | |
11334 if (info.item_compare_func != NULL) | |
11335 { | |
11336 if (*info.item_compare_func == NUL) | |
11337 { | |
11338 /* empty string means default sort */ | |
11339 info.item_compare_func = NULL; | |
11340 } | |
11341 else if (STRCMP(info.item_compare_func, "n") == 0) | |
11342 { | |
11343 info.item_compare_func = NULL; | |
11344 info.item_compare_numeric = TRUE; | |
11345 } | |
11346 else if (STRCMP(info.item_compare_func, "N") == 0) | |
11347 { | |
11348 info.item_compare_func = NULL; | |
11349 info.item_compare_numbers = TRUE; | |
11350 } | |
11351 #ifdef FEAT_FLOAT | |
11352 else if (STRCMP(info.item_compare_func, "f") == 0) | |
11353 { | |
11354 info.item_compare_func = NULL; | |
11355 info.item_compare_float = TRUE; | |
11356 } | |
11357 #endif | |
11358 else if (STRCMP(info.item_compare_func, "i") == 0) | |
11359 { | |
11360 info.item_compare_func = NULL; | |
11361 info.item_compare_ic = TRUE; | |
11362 } | |
11363 } | |
11364 } | |
11365 | |
11366 if (argvars[2].v_type != VAR_UNKNOWN) | |
11367 { | |
11368 /* optional third argument: {dict} */ | |
11369 if (argvars[2].v_type != VAR_DICT) | |
11370 { | |
11371 emsg(_(e_dictreq)); | |
11372 goto theend; | |
11373 } | |
11374 info.item_compare_selfdict = argvars[2].vval.v_dict; | |
11375 } | |
11376 } | |
11377 | |
11378 /* Make an array with each entry pointing to an item in the List. */ | |
11379 ptrs = ALLOC_MULT(sortItem_T, len); | |
11380 if (ptrs == NULL) | |
11381 goto theend; | |
11382 | |
11383 i = 0; | |
11384 if (sort) | |
11385 { | |
11386 /* sort(): ptrs will be the list to sort */ | |
11387 for (li = l->lv_first; li != NULL; li = li->li_next) | |
11388 { | |
11389 ptrs[i].item = li; | |
11390 ptrs[i].idx = i; | |
11391 ++i; | |
11392 } | |
11393 | |
11394 info.item_compare_func_err = FALSE; | |
11395 info.item_compare_keep_zero = FALSE; | |
11396 /* test the compare function */ | |
11397 if ((info.item_compare_func != NULL | |
11398 || info.item_compare_partial != NULL) | |
11399 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) | |
11400 == ITEM_COMPARE_FAIL) | |
11401 emsg(_("E702: Sort compare function failed")); | |
11402 else | |
11403 { | |
11404 /* Sort the array with item pointers. */ | |
11405 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T), | |
11406 info.item_compare_func == NULL | |
11407 && info.item_compare_partial == NULL | |
11408 ? item_compare : item_compare2); | |
11409 | |
11410 if (!info.item_compare_func_err) | |
11411 { | |
11412 /* Clear the List and append the items in sorted order. */ | |
11413 l->lv_first = l->lv_last = l->lv_idx_item = NULL; | |
11414 l->lv_len = 0; | |
11415 for (i = 0; i < len; ++i) | |
11416 list_append(l, ptrs[i].item); | |
11417 } | |
11418 } | |
11419 } | |
11420 else | |
11421 { | |
11422 int (*item_compare_func_ptr)(const void *, const void *); | |
11423 | |
11424 /* f_uniq(): ptrs will be a stack of items to remove */ | |
11425 info.item_compare_func_err = FALSE; | |
11426 info.item_compare_keep_zero = TRUE; | |
11427 item_compare_func_ptr = info.item_compare_func != NULL | |
11428 || info.item_compare_partial != NULL | |
11429 ? item_compare2 : item_compare; | |
11430 | |
11431 for (li = l->lv_first; li != NULL && li->li_next != NULL; | |
11432 li = li->li_next) | |
11433 { | |
11434 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next) | |
11435 == 0) | |
11436 ptrs[i++].item = li; | |
11437 if (info.item_compare_func_err) | |
11438 { | |
11439 emsg(_("E882: Uniq compare function failed")); | |
11440 break; | |
11441 } | |
11442 } | |
11443 | |
11444 if (!info.item_compare_func_err) | |
11445 { | |
11446 while (--i >= 0) | |
11447 { | |
11448 li = ptrs[i].item->li_next; | |
11449 ptrs[i].item->li_next = li->li_next; | |
11450 if (li->li_next != NULL) | |
11451 li->li_next->li_prev = ptrs[i].item; | |
11452 else | |
11453 l->lv_last = ptrs[i].item; | |
11454 list_fix_watch(l, li); | |
11455 listitem_free(li); | |
11456 l->lv_len--; | |
11457 } | |
11458 } | |
11459 } | |
11460 | |
11461 vim_free(ptrs); | |
11462 } | |
11463 theend: | |
11464 sortinfo = old_sortinfo; | |
11465 } | |
11466 | |
11467 /* | |
11468 * "sort({list})" function | |
11469 */ | |
11470 static void | |
11471 f_sort(typval_T *argvars, typval_T *rettv) | |
11472 { | |
11473 do_sort_uniq(argvars, rettv, TRUE); | |
11474 } | |
11475 | |
11476 /* | |
11477 * "uniq({list})" function | |
11478 */ | |
11479 static void | |
11480 f_uniq(typval_T *argvars, typval_T *rettv) | |
11481 { | |
11482 do_sort_uniq(argvars, rettv, FALSE); | |
11483 } | |
11484 | |
11485 /* | 10828 /* |
11486 * "soundfold({word})" function | 10829 * "soundfold({word})" function |
11487 */ | 10830 */ |
11488 static void | 10831 static void |
11489 f_soundfold(typval_T *argvars, typval_T *rettv) | 10832 f_soundfold(typval_T *argvars, typval_T *rettv) |
13480 } | 12823 } |
13481 } | 12824 } |
13482 } | 12825 } |
13483 | 12826 |
13484 /* | 12827 /* |
13485 * "values(dict)" function | |
13486 */ | |
13487 static void | |
13488 f_values(typval_T *argvars, typval_T *rettv) | |
13489 { | |
13490 dict_list(argvars, rettv, 1); | |
13491 } | |
13492 | |
13493 /* | |
13494 * "virtcol(string)" function | 12828 * "virtcol(string)" function |
13495 */ | 12829 */ |
13496 static void | 12830 static void |
13497 f_virtcol(typval_T *argvars, typval_T *rettv) | 12831 f_virtcol(typval_T *argvars, typval_T *rettv) |
13498 { | 12832 { |