csh and tcsh work

Sources of csh/sh.dol.c

csh と tcsh のソース

Bill Joy

First published: October, 1978.

Copyright © 1979 Regents of the University of California.

  1. 1
    /* Copyright (c) 1979 Regents of the University of California */
  2. 2
    #include "sh.h"
  3. 3
  4. 4
    /*
  5. 5
     * C shell
  6. 6
     */
  7. 7
  8. 8
    /*
  9. 9
     * These routines perform variable substitution and quoting via ' and ".
  10. 10
     * To this point these constructs have been preserved in the divided
  11. 11
     * input words.  Here we expand variables and turn quoting via ' and " into
  12. 12
     * QUOTE bits on characters (which prevent further interpretation).
  13. 13
     * If the `:q' modifier was applied during history expansion, then
  14. 14
     * some QUOTEing may have occurred already, so we dont "scan(,&trim)" here.
  15. 15
     */
  16. 16
  17. 17
    int	Dpeekc, Dpeekrd;		/* Peeks for DgetC and Dreadc */
  18. 18
    char	*Dcp, **Dvp;			/* Input vector for Dreadc */
  19. 19
  20. 20
    #define	DEOF	-1
  21. 21
  22. 22
    #define	unDgetC(c)	Dpeekc = c
  23. 23
  24. 24
    char	*QUOTES = "\\'`\"";
  25. 25
  26. 26
    /*
  27. 27
     * The following variables give the information about the current
  28. 28
     * $ expansion, recording the current word position, the remaining
  29. 29
     * words within this expansion, the count of remaining words, and the
  30. 30
     * information about any : modifier which is being applied.
  31. 31
     */
  32. 32
    char	*dolp;			/* Remaining chars from this word */
  33. 33
    char	**dolnxt;		/* Further words */
  34. 34
    int	dolcnt;			/* Count of further words */
  35. 35
    char	dolmod;			/* : modifier character */
  36. 36
    int	dolmcnt;		/* :gx -> 10000, else 1 */
  37. 37
  38. 38
    int	Dtest();		/* Test for \ " ` or ' */
  39. 39
  40. 40
    /*
  41. 41
     * Fix up the $ expansions and quotations in the
  42. 42
     * argument list to command t.
  43. 43
     */
  44. 44
    Dfix(t)
  45. 45
    	register struct command *t;
  46. 46
    {
  47. 47
  48. 48
    	if (noexec)
  49. 49
    		return;
  50. 50
    	gflag = 0, rscan(t->t_dcom, Dtest);
  51. 51
    	if (gflag == 0)
  52. 52
    		return;
  53. 53
    	Dfix2(t->t_dcom);
  54. 54
    	blkfree(t->t_dcom), t->t_dcom = gargv, gargv = 0;
  55. 55
    }
  56. 56
  57. 57
    /*
  58. 58
     * $ substitute one word, for i/o redirection
  59. 59
     */
  60. 60
    char *
  61. 61
    Dfix1(cp)
  62. 62
    	register char *cp;
  63. 63
    {
  64. 64
    	char *Dv[2];
  65. 65
  66. 66
    	if (noexec)
  67. 67
    		return (0);
  68. 68
    	Dv[0] = cp; Dv[1] = NOSTR;
  69. 69
    	Dfix2(Dv);
  70. 70
    	if (gargc != 1) {
  71. 71
    		setname(cp);
  72. 72
    		bferr("Ambiguous");
  73. 73
    	}
  74. 74
    	cp = savestr(gargv[0]);
  75. 75
    	blkfree(gargv), gargv = 0;
  76. 76
    	return (cp);
  77. 77
    }
  78. 78
  79. 79
    /*
  80. 80
     * Subroutine to do actual fixing after state initialization.
  81. 81
     */
  82. 82
    Dfix2(v)
  83. 83
    	char **v;
  84. 84
    {
  85. 85
    	char *agargv[GAVSIZ];
  86. 86
  87. 87
    	ginit(agargv);			/* Initialize glob's area pointers */
  88. 88
    	Dvp = v; Dcp = "";		/* Setup input vector for Dreadc */
  89. 89
    	unDgetC(0); unDredc(0);		/* Clear out any old peeks (at error) */
  90. 90
    	dolp = 0; dolcnt = 0;		/* Clear out residual $ expands (...) */
  91. 91
    	while (Dword())
  92. 92
    		continue;
  93. 93
    	gargv = copyblk(gargv);
  94. 94
    }
  95. 95
  96. 96
    /*
  97. 97
     * Get a word.  This routine is analogous to the routine
  98. 98
     * word() in sh.lex.c for the main lexical input.  One difference
  99. 99
     * here is that we don't get a newline to terminate our expansion.
  100. 100
     * Rather, DgetC will return a DEOF when we hit the end-of-input.
  101. 101
     */
  102. 102
    Dword()
  103. 103
    {
  104. 104
    	register int c, c1;
  105. 105
    	char wbuf[BUFSIZ];
  106. 106
    	register char *wp = wbuf;
  107. 107
    	register int i = BUFSIZ - 4;
  108. 108
    	register bool dolflg;
  109. 109
    	bool sofar = 0;
  110. 110
  111. 111
    loop:
  112. 112
    	c = DgetC(DODOL);
  113. 113
    	switch (c) {
  114. 114
  115. 115
    	case DEOF:
  116. 116
    deof:
  117. 117
    		if (sofar == 0)
  118. 118
    			return (0);
  119. 119
    		/* finish this word and catch the code above the next time */
  120. 120
    		unDredc(c);
  121. 121
    		/* fall into ... */
  122. 122
  123. 123
    	case '\n':
  124. 124
    		*wp = 0;
  125. 125
    		goto ret;
  126. 126
  127. 127
    	case ' ':
  128. 128
    	case '\t':
  129. 129
    		goto loop;
  130. 130
  131. 131
    	case '`':
  132. 132
    		/* We preserve ` quotations which are done yet later */
  133. 133
    		*wp++ = c, --i;
  134. 134
    	case '\'':
  135. 135
    	case '"':
  136. 136
    		/*
  137. 137
    		 * Note that DgetC never returns a QUOTES character
  138. 138
    		 * from an expansion, so only true input quotes will
  139. 139
    		 * get us here or out.
  140. 140
    		 */
  141. 141
    		c1 = c;
  142. 142
    		dolflg = c1 == '"' ? DODOL : 0;
  143. 143
    		for (;;) {
  144. 144
    			c = DgetC(dolflg);
  145. 145
    			if (c == c1)
  146. 146
    				break;
  147. 147
    			if (c == '\n' || c == DEOF)
  148. 148
    				error("Unmatched %c", c1);
  149. 149
    			if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE))
  150. 150
    				--wp, ++i;
  151. 151
    			if (--i <= 0)
  152. 152
    				goto toochars;
  153. 153
    			switch (c1) {
  154. 154
  155. 155
    			case '"':
  156. 156
    				/*
  157. 157
    				 * Leave any `s alone for later.
  158. 158
    				 * Other chars are all quoted, thus `...`
  159. 159
    				 * can tell it was within "...".
  160. 160
    				 */
  161. 161
    				*wp++ = c == '`' ? '`' : c | QUOTE;
  162. 162
    				break;
  163. 163
  164. 164
    			case '\'':
  165. 165
    				/* Prevent all further interpretation */
  166. 166
    				*wp++ = c | QUOTE;
  167. 167
    				break;
  168. 168
  169. 169
    			case '`':
  170. 170
    				/* Leave all text alone for later */
  171. 171
    				*wp++ = c;
  172. 172
    				break;
  173. 173
    			}
  174. 174
    		}
  175. 175
    		if (c1 == '`')
  176. 176
    			*wp++ = '`', --i;
  177. 177
    		goto pack;		/* continue the word */
  178. 178
  179. 179
    	case '\\':
  180. 180
    		c = DgetC(0);		/* No $ subst! */
  181. 181
    		if (c == '\n' || c == DEOF)
  182. 182
    			goto loop;
  183. 183
    		c |= QUOTE;
  184. 184
    		break;
  185. 185
    	}
  186. 186
    	unDgetC(c);
  187. 187
    pack:
  188. 188
    	sofar = 1;
  189. 189
    	/* pack up more characters in this word */
  190. 190
    	for (;;) {
  191. 191
    		c = DgetC(DODOL);
  192. 192
    		if (c == '\\') {
  193. 193
    			c = DgetC(0);
  194. 194
    			if (c == DEOF)
  195. 195
    				goto deof;
  196. 196
    			if (c == '\n')
  197. 197
    				c = ' ';
  198. 198
    			else
  199. 199
    				c |= QUOTE;
  200. 200
    		}
  201. 201
    		if (c == DEOF)
  202. 202
    			goto deof;
  203. 203
    		if (any(c, " '`\"\t\n")) {
  204. 204
    			unDgetC(c);
  205. 205
    			if (any(c, QUOTES))
  206. 206
    				goto loop;
  207. 207
    			*wp++ = 0;
  208. 208
    			goto ret;
  209. 209
    		}
  210. 210
    		if (--i <= 0)
  211. 211
    toochars:
  212. 212
    			error("Word too long");
  213. 213
    		*wp++ = c;
  214. 214
    	}
  215. 215
    ret:
  216. 216
    	Gcat("", wbuf);
  217. 217
    	return (1);
  218. 218
    }
  219. 219
  220. 220
    /*
  221. 221
     * Get a character, performing $ substitution unless flag is 0.
  222. 222
     * Any QUOTES character which is returned from a $ expansion is
  223. 223
     * QUOTEd so that it will not be recognized above.
  224. 224
     */
  225. 225
    DgetC(flag)
  226. 226
    	register int flag;
  227. 227
    {
  228. 228
    	register int c;
  229. 229
  230. 230
    top:
  231. 231
    	if (c = Dpeekc) {
  232. 232
    		Dpeekc = 0;
  233. 233
    		return (c);
  234. 234
    	}
  235. 235
    	if (lap) {
  236. 236
    		c = *lap++;
  237. 237
    		if (c == 0) {
  238. 238
    			lap = 0;
  239. 239
    			goto top;
  240. 240
    		}
  241. 241
    quotspec:
  242. 242
    		if (any(c, QUOTES))
  243. 243
    			return (c | QUOTE);
  244. 244
    		return (c);
  245. 245
    	}
  246. 246
    	if (dolp) {
  247. 247
    		if (c = *dolp++)
  248. 248
    			goto quotspec;
  249. 249
    		if (dolcnt > 0) {
  250. 250
    			setDolp(*dolnxt++);
  251. 251
    			--dolcnt;
  252. 252
    			return (' ');
  253. 253
    		}
  254. 254
    		dolp = 0;
  255. 255
    	}
  256. 256
    	if (dolcnt > 0) {
  257. 257
    		setDolp(*dolnxt++);
  258. 258
    		--dolcnt;
  259. 259
    		goto top;
  260. 260
    	}
  261. 261
    	c = Dredc();
  262. 262
    	if (c == '$' && flag) {
  263. 263
    		Dgetdol();
  264. 264
    		goto top;
  265. 265
    	}
  266. 266
    	return (c);
  267. 267
    }
  268. 268
  269. 269
    char	*nulvec[] = { 0 };
  270. 270
    struct	varent nulargv = { nulvec, "argv", 0 };
  271. 271
  272. 272
    /*
  273. 273
     * Handle the multitudinous $ expansion forms.
  274. 274
     * Ugh.
  275. 275
     */
  276. 276
    Dgetdol()
  277. 277
    {
  278. 278
    	register char *np;
  279. 279
    	register struct varent *vp;
  280. 280
    	char name[20];
  281. 281
    	int c, sc;
  282. 282
    	int subscr = 0, lwb = 1, upb = 0;
  283. 283
    	bool dimen = 0, isset = 0;
  284. 284
  285. 285
    	dolmod = dolmcnt = 0;
  286. 286
    	c = sc = DgetC(0);
  287. 287
    	if (c == '{')
  288. 288
    		c = DgetC(0);		/* sc is { to take } later */
  289. 289
    	if ((c & TRIM) == '#')
  290. 290
    		dimen++, c = DgetC(0);		/* $# takes dimension */
  291. 291
    	else if (c == '?')
  292. 292
    		isset++, c = DgetC(0);		/* $? tests existence */
  293. 293
    	switch (c) {
  294. 294
  295. 295
    	case '$':
  296. 296
    		if (dimen || isset)
  297. 297
    			goto syntax;		/* No $?$, $#$ */
  298. 298
    		setDolp(doldol);
  299. 299
    		goto eatbrac;
  300. 300
  301. 301
    	case DEOF:
  302. 302
    	case '\n':
  303. 303
    		goto syntax;
  304. 304
  305. 305
    	case '*':
  306. 306
    		strcpy(name, "argv");
  307. 307
    		vp = adrof("argv");
  308. 308
    		subscr = -1;			/* Prevent eating [...] */
  309. 309
    		break;
  310. 310
  311. 311
    	default:
  312. 312
    		np = name;
  313. 313
    		if (digit(c)) {
  314. 314
    			if (dimen)
  315. 315
    				goto syntax;	/* No $#1, e.g. */
  316. 316
    			subscr = 0;
  317. 317
    			do {
  318. 318
    				subscr = subscr * 10 + c - '0';
  319. 319
    				c = DgetC(0);
  320. 320
    			} while (digit(c));
  321. 321
    			unDredc(c);
  322. 322
    			if (subscr < 0)
  323. 323
    				goto oob;
  324. 324
    			if (subscr == 0) {
  325. 325
    				if (isset) {
  326. 326
    					dolp = file ? "1" : "0";
  327. 327
    					goto eatbrac;
  328. 328
    				}
  329. 329
    				if (file == 0)
  330. 330
    					error("No file for $0");
  331. 331
    				setDolp(file);
  332. 332
    				goto eatbrac;
  333. 333
    			}
  334. 334
    			if (isset)
  335. 335
    				goto syntax;
  336. 336
    			vp = adrof("argv");
  337. 337
    			if (vp == 0) {
  338. 338
    				vp = &nulargv;
  339. 339
    				goto eatmod;
  340. 340
    			}
  341. 341
    			break;
  342. 342
    		}
  343. 343
    		if (!letter(c))
  344. 344
    			goto syntax;
  345. 345
    		for (;;) {
  346. 346
    			*np++ = c;
  347. 347
    			c = DgetC(0);
  348. 348
    			if (!letter(c))
  349. 349
    				break;
  350. 350
    			if (np >= &name[sizeof name - 2])
  351. 351
    syntax:
  352. 352
    				error("Variable syntax");
  353. 353
    		}
  354. 354
    		*np++ = 0;
  355. 355
    		unDredc(c);
  356. 356
    		vp = adrof(name);
  357. 357
    	}
  358. 358
    	if (isset) {
  359. 359
    		dolp = vp ? "1" : "0";
  360. 360
    		goto eatbrac;
  361. 361
    	}
  362. 362
    	if (vp == 0)
  363. 363
    		udvar(name);
  364. 364
    	c = DgetC(0);
  365. 365
    	upb = blklen(vp->vec);
  366. 366
    	if (dimen == 0 && subscr == 0 && c == '[') {
  367. 367
    		np = name;
  368. 368
    		for (;;) {
  369. 369
    			c = DgetC(DODOL);	/* Allow $ expand within [ ] */
  370. 370
    			if (c == ']')
  371. 371
    				break;
  372. 372
    			if (c == '\n' || c == DEOF)
  373. 373
    				goto syntax;
  374. 374
    			if (np >= &name[sizeof name - 2])
  375. 375
    				goto syntax;
  376. 376
    			*np++ = c;
  377. 377
    		}
  378. 378
    		*np = 0, np = name;
  379. 379
    		if (dolp || dolcnt)		/* $ exp must end before ] */
  380. 380
    			goto syntax;
  381. 381
    		if (!*np)
  382. 382
    			goto syntax;
  383. 383
    		if (digit(*np)) {
  384. 384
    			register int i = 0;
  385. 385
  386. 386
    			while (digit(*np))
  387. 387
    				i = i * 10 + *np++ - '0';
  388. 388
    			if ((i < 0 || i > upb) && !any(*np, "-*")) {
  389. 389
    oob:
  390. 390
    				setname(vp->name);
  391. 391
    				error("Subscript out of range");
  392. 392
    			}
  393. 393
    			lwb = i;
  394. 394
    			if (!*np)
  395. 395
    				upb = lwb, np = "*";
  396. 396
    		}
  397. 397
    		if (*np == '*')
  398. 398
    			np++;
  399. 399
    		else if (*np != '-')
  400. 400
    			goto syntax;
  401. 401
    		else {
  402. 402
    			register int i = upb;
  403. 403
  404. 404
    			np++;
  405. 405
    			if (digit(*np)) {
  406. 406
    				i = 0;
  407. 407
    				while (digit(*np))
  408. 408
    					i = i * 10 + *np++ - '0';
  409. 409
    				if (i < 0 || i > upb)
  410. 410
    					goto oob;
  411. 411
    			}
  412. 412
    			if (i < lwb)
  413. 413
    				upb = lwb - 1;
  414. 414
    			else
  415. 415
    				upb = i;
  416. 416
    		}
  417. 417
    		if (lwb == 0) {
  418. 418
    			if (upb != 0)
  419. 419
    				goto oob;
  420. 420
    			upb = -1;
  421. 421
    		}
  422. 422
    		if (*np)
  423. 423
    			goto syntax;
  424. 424
    	} else {
  425. 425
    		if (subscr > 0)
  426. 426
    			if (subscr > upb)
  427. 427
    				lwb = 1, upb = 0;
  428. 428
    			else
  429. 429
    				lwb = upb = subscr;
  430. 430
    		unDredc(c);
  431. 431
    	}
  432. 432
    	if (dimen) {
  433. 433
    		char *cp = putn(upb - lwb + 1);
  434. 434
  435. 435
    		addla(cp);
  436. 436
    		xfree(cp);
  437. 437
    	} else {
  438. 438
    eatmod:
  439. 439
    		c = DgetC(0);
  440. 440
    		if (c == ':') {
  441. 441
    			c = DgetC(0), dolmcnt = 1;
  442. 442
    			if (c == 'g')
  443. 443
    				c = DgetC(0), dolmcnt = 10000;
  444. 444
    			if (!any(c, "htrqx"))
  445. 445
    				error("Bad : mod in $");
  446. 446
    			dolmod = c;
  447. 447
    			if (c == 'q')
  448. 448
    				dolmcnt = 10000;
  449. 449
    		} else
  450. 450
    			unDredc(c);
  451. 451
    		dolnxt = &vp->vec[lwb - 1];
  452. 452
    		dolcnt = upb - lwb + 1;
  453. 453
    	}
  454. 454
    eatbrac:
  455. 455
    	if (sc == '{') {
  456. 456
    		c = Dredc();
  457. 457
    		if (c != '}')
  458. 458
    			goto syntax;
  459. 459
    	}
  460. 460
    }
  461. 461
  462. 462
    setDolp(cp)
  463. 463
    	register char *cp;
  464. 464
    {
  465. 465
    	register char *dp;
  466. 466
  467. 467
    	if (dolmod == 0 || dolmcnt == 0) {
  468. 468
    		dolp = cp;
  469. 469
    		return;
  470. 470
    	}
  471. 471
    	dp = domod(cp, dolmod);
  472. 472
    	if (dp) {
  473. 473
    		dolmcnt--;
  474. 474
    		addla(dp);
  475. 475
    		xfree(dp);
  476. 476
    	} else
  477. 477
    		addla(cp);
  478. 478
    	dolp = "";
  479. 479
    }
  480. 480
  481. 481
    unDredc(c)
  482. 482
    	int c;
  483. 483
    {
  484. 484
  485. 485
    	Dpeekrd = c;
  486. 486
    }
  487. 487
  488. 488
    Dredc()
  489. 489
    {
  490. 490
    	register int c;
  491. 491
  492. 492
    	if (c = Dpeekrd) {
  493. 493
    		Dpeekrd = 0;
  494. 494
    		return (c);
  495. 495
    	}
  496. 496
    	if (Dcp && (c = *Dcp++))
  497. 497
    		return (c);
  498. 498
    	if (*Dvp == 0) {
  499. 499
    		Dcp = 0;
  500. 500
    		return (DEOF);
  501. 501
    	}
  502. 502
    	Dcp = *Dvp++;
  503. 503
    	return (' ');
  504. 504
    }
  505. 505
  506. 506
    Dtest(c)
  507. 507
    	register int c;
  508. 508
    {
  509. 509
  510. 510
    	/* Note that c isn't trimmed thus !...:q's aren't lost */
  511. 511
    	if (any(c, "$\\'`\""))
  512. 512
    		gflag = 1;
  513. 513
    }
  514. 514
  515. 515
    Dtestq(c)
  516. 516
    	register int c;
  517. 517
    {
  518. 518
  519. 519
    	if (any(c, "\\'`\""))
  520. 520
    		gflag = 1;
  521. 521
    }
  522. 522
  523. 523
    /*
  524. 524
     * Form a shell temporary file (in unit 0) from the words
  525. 525
     * of the shell input up to a line the same as "term".
  526. 526
     * Unit 0 should have been closed before this call.
  527. 527
     */
  528. 528
    heredoc(term)
  529. 529
    	char *term;
  530. 530
    {
  531. 531
    	register int c;
  532. 532
    	char *Dv[2];
  533. 533
    	char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
  534. 534
    	int ocnt, lcnt, mcnt;
  535. 535
    	register char *lbp, *obp, *mbp;
  536. 536
    	char **vp;
  537. 537
    	bool quoted;
  538. 538
  539. 539
    	if (creat(shtemp, 0600) < 0)
  540. 540
    		Perror(shtemp);
  541. 541
    	close(0);
  542. 542
    	if (open(shtemp, 2) < 0) {
  543. 543
    		int oerrno = errno;
  544. 544
  545. 545
    		unlink(shtemp);
  546. 546
    		errno = oerrno;
  547. 547
    		Perror(shtemp);
  548. 548
    	}
  549. 549
    	unlink(shtemp);			/* 0 0 inode! */
  550. 550
    	Dv[0] = term; Dv[1] = NOSTR; gflag = 0;
  551. 551
    	scan(Dv, trim); rscan(Dv, Dtestq); quoted = gflag;
  552. 552
    	ocnt = BUFSIZ; obp = obuf;
  553. 553
    	for (;;) {
  554. 554
    		/*
  555. 555
    		 * Read up a line
  556. 556
    		 */
  557. 557
    		lbp = lbuf; lcnt = BUFSIZ - 4;
  558. 558
    		for (;;) {
  559. 559
    			c = readc(1);		/* 1 -> Want EOF returns */
  560. 560
    			if (c < 0) {
  561. 561
    				setname(term);
  562. 562
    				bferr("<< terminator not found");
  563. 563
    			}
  564. 564
    			if (c == '\n')
  565. 565
    				break;
  566. 566
    			if (c &= TRIM) {
  567. 567
    				*lbp++ = c;
  568. 568
    				if (--lcnt < 0) {
  569. 569
    					setname("<<");
  570. 570
    					error("Line overflow");
  571. 571
    				}
  572. 572
    			}
  573. 573
    		}
  574. 574
    		*lbp = 0;
  575. 575
  576. 576
    		/*
  577. 577
    		 * Compare to terminator -- before expansion
  578. 578
    		 */
  579. 579
    		if (eq(lbuf, term)) {
  580. 580
    			write(0, obuf, BUFSIZ - ocnt);
  581. 581
    			lseek(0, 0l, 0);
  582. 582
    			return;
  583. 583
    		}
  584. 584
  585. 585
    		/*
  586. 586
    		 * If term was quoted or -n just pass it on
  587. 587
    		 */
  588. 588
    		if (quoted || noexec) {
  589. 589
    			*lbp++ = '\n'; *lbp = 0;
  590. 590
    			for (lbp = lbuf; c = *lbp++;) {
  591. 591
    				*obp++ = c;
  592. 592
    				if (--ocnt == 0) {
  593. 593
    					write(0, obuf, BUFSIZ);
  594. 594
    					obp = obuf; ocnt = BUFSIZ;
  595. 595
    				}
  596. 596
    			}
  597. 597
    			continue;
  598. 598
    		}
  599. 599
  600. 600
    		/*
  601. 601
    		 * Term wasn't quoted so variable and then command
  602. 602
    		 * expand the input line
  603. 603
    		 */
  604. 604
    		Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4;
  605. 605
    		for (;;) {
  606. 606
    			c = DgetC(DODOL);
  607. 607
    			if (c == DEOF)
  608. 608
    				break;
  609. 609
    			if ((c &= TRIM) == 0)
  610. 610
    				continue;
  611. 611
    			/* \ quotes \ $ ` here */
  612. 612
    			if (c =='\\') {
  613. 613
    				c = DgetC(0);
  614. 614
    				if (!any(c, "$\\`"))
  615. 615
    					unDgetC(c | QUOTE), c = '\\';
  616. 616
    				else
  617. 617
    					c |= QUOTE;
  618. 618
    			}
  619. 619
    			*mbp++ = c;
  620. 620
    			if (--mcnt == 0) {
  621. 621
    				setname("<<");
  622. 622
    				bferr("Line overflow");
  623. 623
    			}
  624. 624
    		}
  625. 625
    		*mbp++ = 0;
  626. 626
  627. 627
    		/*
  628. 628
    		 * If any ` in line do command substitution
  629. 629
    		 */
  630. 630
    		mbp = mbuf;
  631. 631
    		if (any('`', mbp)) {
  632. 632
    			/*
  633. 633
    			 * 1 arg to dobackp causes substitution to be literal.
  634. 634
    			 * Words are broken only at newlines so that all blanks
  635. 635
    			 * and tabs are preserved.  Blank lines (null words)
  636. 636
    			 * are not discarded.
  637. 637
    			 */
  638. 638
    			vp = dobackp(mbuf, 1);
  639. 639
    		} else
  640. 640
    			/* Setup trivial vector similar to return of dobackp */
  641. 641
    			Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv;
  642. 642
  643. 643
    		/*
  644. 644
    		 * Resurrect the words from the command substitution
  645. 645
    		 * each separated by a newline.  Note that the last
  646. 646
    		 * newline of a command substitution will have been
  647. 647
    		 * discarded, but we put a newline after the last word
  648. 648
    		 * because this represents the newline after the last
  649. 649
    		 * input line!
  650. 650
    		 */
  651. 651
    		for (; *vp; vp++) {
  652. 652
    			for (mbp = *vp; *mbp; mbp++) {
  653. 653
    				*obp++ = *mbp & TRIM;
  654. 654
    				if (--ocnt == 0) {
  655. 655
    					write(0, obuf, BUFSIZ);
  656. 656
    					obp = obuf; ocnt = BUFSIZ;
  657. 657
    				}
  658. 658
    			}
  659. 659
    			*obp++ = '\n';
  660. 660
    			if (--ocnt == 0) {
  661. 661
    				write(0, obuf, BUFSIZ);
  662. 662
    				obp = obuf; ocnt = BUFSIZ;
  663. 663
    			}
  664. 664
    		}
  665. 665
    		if (pargv)
  666. 666
    			blkfree(pargv), pargv = 0;
  667. 667
    	}
  668. 668
    }

To the top of this page