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 {