1 /* $NetBSD: api.c,v 1.3 2013/11/25 22:43:46 christos Exp $ */ 2 /*- 3 * Copyright (c) 1992, 1993, 1994 4 * The Regents of the University of California. All rights reserved. 5 * Copyright (c) 1992, 1993, 1994, 1995, 1996 6 * Keith Bostic. All rights reserved. 7 * Copyright (c) 1995 8 * George V. Neville-Neil. All rights reserved. 9 * 10 * See the LICENSE file for redistribution information. 11 */ 12 13 #include "config.h" 14 15 #ifndef lint 16 static const char sccsid[] = "Id: api.c,v 8.40 2002/06/08 19:30:33 skimo Exp (Berkeley) Date: 2002/06/08 19:30:33 "; 17 #endif /* not lint */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/time.h> 22 23 #include <bitstring.h> 24 #include <limits.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <termios.h> 29 #include <unistd.h> 30 31 #include "../common/common.h" 32 #include "../ex/tag.h" 33 34 extern GS *__global_list; /* XXX */ 35 36 /* 37 * api_fscreen -- 38 * Return a pointer to the screen specified by the screen id 39 * or a file name. 40 * 41 * PUBLIC: SCR *api_fscreen __P((int, char *)); 42 */ 43 SCR * 44 api_fscreen(int id, char *name) 45 { 46 GS *gp; 47 SCR *tsp; 48 WIN *wp; 49 50 gp = __global_list; 51 52 /* Search the displayed lists. */ 53 TAILQ_FOREACH(wp, &gp->dq, q) 54 TAILQ_FOREACH(tsp, &wp->scrq, q) 55 if (name == NULL) { 56 if (id == tsp->id) 57 return (tsp); 58 } else if (!strcmp(name, tsp->frp->name)) 59 return (tsp); 60 61 /* Search the hidden list. */ 62 TAILQ_FOREACH (tsp, &gp->hq, q) 63 if (name == NULL) { 64 if (id == tsp->id) 65 return (tsp); 66 } else if (!strcmp(name, tsp->frp->name)) 67 return (tsp); 68 return (NULL); 69 } 70 71 /* 72 * api_aline -- 73 * Append a line. 74 * 75 * PUBLIC: int api_aline __P((SCR *, db_recno_t, char *, size_t)); 76 */ 77 int 78 api_aline(SCR *sp, db_recno_t lno, char *line, size_t len) 79 { 80 size_t wblen; 81 const CHAR_T *wbp; 82 83 CHAR2INT(sp, line, len, wbp, wblen); 84 85 return (db_append(sp, 1, lno, wbp, wblen)); 86 } 87 88 /* 89 * api_extend -- 90 * Extend file. 91 * 92 * PUBLIC: int api_extend __P((SCR *, db_recno_t)); 93 */ 94 int 95 api_extend(SCR *sp, db_recno_t lno) 96 { 97 db_recno_t lastlno; 98 if (db_last(sp, &lastlno)) 99 return 1; 100 while(lastlno < lno) 101 if (db_append(sp, 1, lastlno++, NULL, 0)) 102 return 1; 103 return 0; 104 } 105 106 /* 107 * api_dline -- 108 * Delete a line. 109 * 110 * PUBLIC: int api_dline __P((SCR *, db_recno_t)); 111 */ 112 int 113 api_dline(SCR *sp, db_recno_t lno) 114 { 115 if (db_delete(sp, lno)) 116 return 1; 117 /* change current line if deleted line is that one 118 * or one berfore that 119 */ 120 if (sp->lno >= lno && sp->lno > 1) 121 sp->lno--; 122 return 0; 123 } 124 125 /* 126 * api_gline -- 127 * Get a line. 128 * 129 * PUBLIC: int api_gline __P((SCR *, db_recno_t, CHAR_T **, size_t *)); 130 */ 131 int 132 api_gline(SCR *sp, db_recno_t lno, CHAR_T **linepp, size_t *lenp) 133 { 134 int isempty; 135 136 if (db_eget(sp, lno, linepp, lenp, &isempty)) { 137 if (isempty) 138 msgq(sp, M_ERR, "209|The file is empty"); 139 return (1); 140 } 141 return (0); 142 } 143 144 /* 145 * api_iline -- 146 * Insert a line. 147 * 148 * PUBLIC: int api_iline __P((SCR *, db_recno_t, CHAR_T *, size_t)); 149 */ 150 int 151 api_iline(SCR *sp, db_recno_t lno, CHAR_T *line, size_t len) 152 { 153 return (db_insert(sp, lno, line, len)); 154 } 155 156 /* 157 * api_lline -- 158 * Return the line number of the last line in the file. 159 * 160 * PUBLIC: int api_lline __P((SCR *, db_recno_t *)); 161 */ 162 int 163 api_lline(SCR *sp, db_recno_t *lnop) 164 { 165 return (db_last(sp, lnop)); 166 } 167 168 /* 169 * api_sline -- 170 * Set a line. 171 * 172 * PUBLIC: int api_sline __P((SCR *, db_recno_t, CHAR_T *, size_t)); 173 */ 174 int 175 api_sline(SCR *sp, db_recno_t lno, CHAR_T *line, size_t len) 176 { 177 return (db_set(sp, lno, line, len)); 178 } 179 180 /* 181 * api_getmark -- 182 * Get the mark. 183 * 184 * PUBLIC: int api_getmark __P((SCR *, int, MARK *)); 185 */ 186 int 187 api_getmark(SCR *sp, int markname, MARK *mp) 188 { 189 return (mark_get(sp, (ARG_CHAR_T)markname, mp, M_ERR)); 190 } 191 192 /* 193 * api_setmark -- 194 * Set the mark. 195 * 196 * PUBLIC: int api_setmark __P((SCR *, int, MARK *)); 197 */ 198 int 199 api_setmark(SCR *sp, int markname, MARK *mp) 200 { 201 return (mark_set(sp, (ARG_CHAR_T)markname, mp, 1)); 202 } 203 204 /* 205 * api_nextmark -- 206 * Return the first mark if next not set, otherwise return the 207 * subsequent mark. 208 * 209 * PUBLIC: int api_nextmark __P((SCR *, int, char *)); 210 */ 211 int 212 api_nextmark(SCR *sp, int next, char *namep) 213 { 214 LMARK *mp; 215 216 mp = LIST_FIRST(&sp->ep->marks); 217 if (next) 218 for (; mp != NULL; mp = LIST_NEXT(mp, q)) 219 if (mp->name == *namep) { 220 mp = LIST_NEXT(mp, q); 221 break; 222 } 223 if (mp == NULL) 224 return (1); 225 *namep = mp->name; 226 return (0); 227 } 228 229 /* 230 * api_getcursor -- 231 * Get the cursor. 232 * 233 * PUBLIC: int api_getcursor __P((SCR *, MARK *)); 234 */ 235 int 236 api_getcursor(SCR *sp, MARK *mp) 237 { 238 mp->lno = sp->lno; 239 mp->cno = sp->cno; 240 return (0); 241 } 242 243 /* 244 * api_setcursor -- 245 * Set the cursor. 246 * 247 * PUBLIC: int api_setcursor __P((SCR *, MARK *)); 248 */ 249 int 250 api_setcursor(SCR *sp, MARK *mp) 251 { 252 size_t len; 253 254 if (db_get(sp, mp->lno, DBG_FATAL, NULL, &len)) 255 return (1); 256 if (mp->cno > len) { 257 msgq(sp, M_ERR, "Cursor set to nonexistent column"); 258 return (1); 259 } 260 261 /* Set the cursor. */ 262 sp->lno = mp->lno; 263 sp->cno = mp->cno; 264 return (0); 265 } 266 267 /* 268 * api_emessage -- 269 * Print an error message. 270 * 271 * PUBLIC: void api_emessage __P((SCR *, char *)); 272 */ 273 void 274 api_emessage(SCR *sp, char *text) 275 { 276 msgq(sp, M_ERR, "%s", text); 277 } 278 279 /* 280 * api_imessage -- 281 * Print an informational message. 282 * 283 * PUBLIC: void api_imessage __P((SCR *, char *)); 284 */ 285 void 286 api_imessage(SCR *sp, char *text) 287 { 288 msgq(sp, M_INFO, "%s", text); 289 } 290 291 /* 292 * api_edit 293 * Create a new screen and return its id 294 * or edit a new file in the current screen. 295 * 296 * PUBLIC: int api_edit __P((SCR *, char *, SCR **, int)); 297 */ 298 int 299 api_edit(SCR *sp, char *file, SCR **spp, int newscreen) 300 { 301 EXCMD cmd; 302 size_t wlen; 303 const CHAR_T *wp; 304 305 if (file) { 306 ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0); 307 CHAR2INT(sp, file, strlen(file) + 1, wp, wlen); 308 argv_exp0(sp, &cmd, wp, wlen - 1 /* terminating 0 */); 309 } else 310 ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0); 311 if (newscreen) 312 cmd.flags |= E_NEWSCREEN; /* XXX */ 313 if (cmd.cmd->fn(sp, &cmd)) 314 return (1); 315 *spp = sp->nextdisp; 316 return (0); 317 } 318 319 /* 320 * api_escreen 321 * End a screen. 322 * 323 * PUBLIC: int api_escreen __P((SCR *)); 324 */ 325 int 326 api_escreen(SCR *sp) 327 { 328 EXCMD cmd; 329 330 /* 331 * XXX 332 * If the interpreter exits anything other than the current 333 * screen, vi isn't going to update everything correctly. 334 */ 335 ex_cinit(sp, &cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0); 336 return (cmd.cmd->fn(sp, &cmd)); 337 } 338 339 /* 340 * api_swscreen -- 341 * Switch to a new screen. 342 * 343 * PUBLIC: int api_swscreen __P((SCR *, SCR *)); 344 */ 345 int 346 api_swscreen(SCR *sp, SCR *new) 347 { 348 /* 349 * XXX 350 * If the interpreter switches from anything other than the 351 * current screen, vi isn't going to update everything correctly. 352 */ 353 sp->nextdisp = new; 354 F_SET(sp, SC_SSWITCH); 355 356 return (0); 357 } 358 359 /* 360 * api_map -- 361 * Map a key. 362 * 363 * PUBLIC: int api_map __P((SCR *, char *, char *, size_t)); 364 */ 365 int 366 api_map(SCR *sp, char *name, char *map, size_t len) 367 { 368 EXCMD cmd; 369 size_t wlen; 370 const CHAR_T *wp; 371 372 ex_cinit(sp, &cmd, C_MAP, 0, OOBLNO, OOBLNO, 0); 373 CHAR2INT(sp, name, strlen(name) + 1, wp, wlen); 374 argv_exp0(sp, &cmd, wp, wlen - 1); 375 CHAR2INT(sp, map, len, wp, wlen); 376 argv_exp0(sp, &cmd, wp, wlen); 377 return (cmd.cmd->fn(sp, &cmd)); 378 } 379 380 /* 381 * api_unmap -- 382 * Unmap a key. 383 * 384 * PUBLIC: int api_unmap __P((SCR *, char *)); 385 */ 386 int 387 api_unmap(SCR *sp, char *name) 388 { 389 EXCMD cmd; 390 size_t wlen; 391 const CHAR_T *wp; 392 393 ex_cinit(sp, &cmd, C_UNMAP, 0, OOBLNO, OOBLNO, 0); 394 CHAR2INT(sp, name, strlen(name) + 1, wp, wlen); 395 argv_exp0(sp, &cmd, wp, wlen - 1); 396 return (cmd.cmd->fn(sp, &cmd)); 397 } 398 399 /* 400 * api_opts_get -- 401 * Return a option value as a string, in allocated memory. 402 * If the option is of type boolean, boolvalue is (un)set 403 * according to the value; otherwise boolvalue is -1. 404 * 405 * PUBLIC: int api_opts_get __P((SCR *, const CHAR_T *, char **, int *)); 406 */ 407 int 408 api_opts_get(SCR *sp, const CHAR_T *name, char **value, int *boolvalue) 409 { 410 OPTLIST const *op; 411 int offset; 412 413 if ((op = opts_search(name)) == NULL) { 414 opts_nomatch(sp, name); 415 return (1); 416 } 417 418 offset = op - optlist; 419 if (boolvalue != NULL) 420 *boolvalue = -1; 421 switch (op->type) { 422 case OPT_0BOOL: 423 case OPT_1BOOL: 424 MALLOC_RET(sp, *value, char *, STRLEN(op->name) + 2 + 1); 425 (void)sprintf(*value, 426 "%s"WS, O_ISSET(sp, offset) ? "" : "no", op->name); 427 if (boolvalue != NULL) 428 *boolvalue = O_ISSET(sp, offset); 429 break; 430 case OPT_NUM: 431 MALLOC_RET(sp, *value, char *, 20); 432 (void)sprintf(*value, "%lu", (u_long)O_VAL(sp, offset)); 433 break; 434 case OPT_STR: 435 if (O_STR(sp, offset) == NULL) { 436 MALLOC_RET(sp, *value, char *, 2); 437 value[0][0] = '\0'; 438 } else { 439 MALLOC_RET(sp, 440 *value, char *, strlen(O_STR(sp, offset)) + 1); 441 (void)sprintf(*value, "%s", O_STR(sp, offset)); 442 } 443 break; 444 } 445 return (0); 446 } 447 448 /* 449 * api_opts_set -- 450 * Set options. 451 * 452 * PUBLIC: int api_opts_set __P((SCR *, const CHAR_T *, const char *, u_long, int)); 453 */ 454 int 455 api_opts_set(SCR *sp, const CHAR_T *name, 456 const char *str_value, u_long num_value, int bool_value) 457 { 458 ARGS *ap[2], a, b; 459 OPTLIST const *op; 460 int rval; 461 size_t blen; 462 CHAR_T *bp; 463 464 if ((op = opts_search(name)) == NULL) { 465 opts_nomatch(sp, name); 466 return (1); 467 } 468 469 switch (op->type) { 470 case OPT_0BOOL: 471 case OPT_1BOOL: 472 GET_SPACE_RETW(sp, bp, blen, 64); 473 a.len = SPRINTF(bp, 64, L("%s"WS), bool_value ? "" : "no", name); 474 break; 475 case OPT_NUM: 476 GET_SPACE_RETW(sp, bp, blen, 64); 477 a.len = SPRINTF(bp, 64, L(""WS"=%lu"), name, num_value); 478 break; 479 case OPT_STR: 480 GET_SPACE_RETW(sp, bp, blen, 1024); 481 a.len = SPRINTF(bp, 1024, L(""WS"=%s"), name, str_value); 482 break; 483 default: 484 bp = NULL; 485 break; 486 } 487 488 a.bp = bp; 489 b.len = 0; 490 b.bp = NULL; 491 ap[0] = &a; 492 ap[1] = &b; 493 rval = opts_set(sp, ap, NULL); 494 495 FREE_SPACEW(sp, bp, blen); 496 497 return (rval); 498 } 499 500 /* 501 * api_run_str -- 502 * Execute a string as an ex command. 503 * 504 * PUBLIC: int api_run_str __P((SCR *, char *)); 505 */ 506 int 507 api_run_str(SCR *sp, char *cmd) 508 { 509 size_t wlen; 510 const CHAR_T *wp; 511 512 CHAR2INT(sp, cmd, strlen(cmd)+1, wp, wlen); 513 return (ex_run_str(sp, NULL, wp, wlen - 1, 0, 0)); 514 } 515 516 /* 517 * PUBLIC: TAGQ * api_tagq_new __P((SCR*, char*)); 518 */ 519 TAGQ * 520 api_tagq_new(SCR *sp, char *tag) 521 { 522 TAGQ *tqp; 523 size_t len; 524 525 /* Allocate and initialize the tag queue structure. */ 526 len = strlen(tag); 527 CALLOC_GOTO(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + len + 1); 528 TAILQ_INIT(&tqp->tagq); 529 tqp->tag = tqp->buf; 530 memcpy(tqp->tag, tag, (tqp->tlen = len) + 1); 531 532 return tqp; 533 534 alloc_err: 535 return (NULL); 536 } 537 538 /* 539 * PUBLIC: void api_tagq_add __P((SCR*, TAGQ*, char*, char *, char *)); 540 */ 541 void 542 api_tagq_add(SCR *sp, TAGQ *tqp, char *filename, char *search, char *msg) 543 { 544 TAG *tp; 545 const CHAR_T *wp; 546 size_t wlen; 547 size_t flen = strlen(filename); 548 size_t slen = strlen(search); 549 size_t mlen = strlen(msg); 550 551 CALLOC_GOTO(sp, tp, TAG *, 1, 552 sizeof(TAG) - 1 + flen + 1 + 553 (slen + 1 + mlen + 1) * sizeof(CHAR_T)); 554 tp->fname = (char *)tp->buf; 555 memcpy(tp->fname, filename, flen + 1); 556 tp->fnlen = flen; 557 tp->search = (CHAR_T *)((char *)tp->fname + flen + 1); 558 CHAR2INT(sp, search, slen + 1, wp, wlen); 559 MEMCPYW(tp->search, wp, wlen); 560 tp->slen = slen; 561 tp->msg = tp->search + slen + 1; 562 CHAR2INT(sp, msg, mlen + 1, wp, wlen); 563 MEMCPYW(tp->msg, wp, wlen); 564 tp->mlen = mlen; 565 TAILQ_INSERT_TAIL(&tqp->tagq, tp, q); 566 567 alloc_err: 568 return; 569 } 570 571 /* 572 * PUBLIC: int api_tagq_push __P((SCR*, TAGQ**)); 573 */ 574 int 575 api_tagq_push(SCR *sp, TAGQ **tqpp) 576 { 577 TAGQ *tqp; 578 579 tqp = *tqpp; 580 581 *tqpp = 0; 582 583 /* Check to see if we found anything. */ 584 if (TAILQ_EMPTY(&tqp->tagq)) { 585 free(tqp); 586 return 0; 587 } 588 589 tqp->current = TAILQ_FIRST(&tqp->tagq); 590 591 if (tagq_push(sp, tqp, 0, 0)) 592 return 1; 593 594 return (0); 595 } 596 597 /* 598 * PUBLIC: void api_tagq_free __P((SCR*, TAGQ*)); 599 */ 600 void 601 api_tagq_free(SCR *sp, TAGQ *tqp) 602 { 603 if (tqp) 604 tagq_free(sp, tqp); 605 } 606