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