csh and tcsh work

Sources of csh/sh.lex.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 lexical routines read input and form lists of words.
  10. 10
     * There is some involved processing here, because of the complications
  11. 11
     * of input buffering, and especially because of history substitution.
  12. 12
     */
  13. 13
  14. 14
    char	*word();
  15. 15
  16. 16
    /*
  17. 17
     * Peekc is a peek characer for getC, peekread for readc.
  18. 18
     * There is a subtlety here in many places... history routines
  19. 19
     * will read ahead and then insert stuff into the input stream.
  20. 20
     * If they push back a character then they must push it behind
  21. 21
     * the text substituted by the history substitution.  On the other
  22. 22
     * hand in several places we need 2 peek characters.  To make this
  23. 23
     * all work, the history routines read with getC, and make use both
  24. 24
     * of ungetC and unreadc.  The key observation is that the state
  25. 25
     * of getC at the call of a history reference is such that calls
  26. 26
     * to getC from the history routines will always yield calls of
  27. 27
     * readc, unless this peeking is involved.  That is to say that during
  28. 28
     * getexcl the variables lap, exclp, and exclnxt are all zero.
  29. 29
     *
  30. 30
     * Getdol invokes history substitution, hence the extra peek, peekd,
  31. 31
     * which it can ungetD to be before history substitutions.
  32. 32
     */
  33. 33
    char	peekc, peekd;
  34. 34
    char	peekread;
  35. 35
  36. 36
    char	*exclp;			/* (Tail of) current word from ! subst */
  37. 37
    struct	wordent *exclnxt;	/* The rest of the ! subst words */
  38. 38
    int	exclc;			/* Count of remainig words in ! subst */
  39. 39
    char	*alvecp;		/* "Globp" for alias resubstitution */
  40. 40
  41. 41
    /*
  42. 42
     * Lex returns to its caller not only a wordlist (as a "var" parameter)
  43. 43
     * but also whether a history substitution occurred.  This is used in
  44. 44
     * the main (process) routine to determine whether to echo, and also
  45. 45
     * when called by the alias routine to determine whether to keep the
  46. 46
     * argument list.
  47. 47
     */
  48. 48
    bool	hadhist;
  49. 49
  50. 50
    #define	ungetC(c)	peekc = c
  51. 51
    #define	ungetD(c)	peekd = c
  52. 52
  53. 53
    lex(hp)
  54. 54
    	register struct wordent *hp;
  55. 55
    {
  56. 56
    	register struct wordent *wdp;
  57. 57
    	int c;
  58. 58
  59. 59
    	lineloc = btell();
  60. 60
    	hp->next = hp->prev = hp;
  61. 61
    	hp->word = "";
  62. 62
    	alvecp = 0, hadhist = 0;
  63. 63
    	do
  64. 64
    		c = readc(0);
  65. 65
    	while (c == ' ' || c == '\t');
  66. 66
    	if (c == '^' && intty)
  67. 67
    		/* ^lef^rit	from tty is short !:s^lef^rit */
  68. 68
    		getexcl(c);
  69. 69
    	else
  70. 70
    		unreadc(c);
  71. 71
    	wdp = hp;
  72. 72
    	/*
  73. 73
    	 * The following loop is written so that the links needed
  74. 74
    	 * by freelex will be ready and rarin to go even if it is
  75. 75
    	 * interrupted.
  76. 76
    	 */
  77. 77
    	do {
  78. 78
    		register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
  79. 79
  80. 80
    		new->prev = wdp;
  81. 81
    		new->next = hp;
  82. 82
    		wdp->next = new;
  83. 83
    		wdp = new;
  84. 84
    		wdp->word = word();
  85. 85
    	} while (wdp->word[0] != '\n');
  86. 86
    	hp->prev = wdp;
  87. 87
    	return (hadhist);
  88. 88
    }
  89. 89
  90. 90
    prlex(sp0)
  91. 91
    	struct wordent *sp0;
  92. 92
    {
  93. 93
    	register struct wordent *sp = sp0->next;
  94. 94
  95. 95
    	for (;;) {
  96. 96
    		printf("%s", sp->word);
  97. 97
    		sp = sp->next;
  98. 98
    		if (sp == sp0)
  99. 99
    			break;
  100. 100
    		printf(" ");
  101. 101
    	}
  102. 102
    }
  103. 103
  104. 104
    copylex(hp, fp)
  105. 105
    	register struct wordent *hp;
  106. 106
    	struct wordent *fp;
  107. 107
    {
  108. 108
    	register struct wordent *wdp;
  109. 109
  110. 110
    	wdp = hp;
  111. 111
    	fp = fp->next;
  112. 112
    	do {
  113. 113
    		register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
  114. 114
  115. 115
    		new->prev = wdp;
  116. 116
    		new->next = hp;
  117. 117
    		wdp->next = new;
  118. 118
    		wdp = new;
  119. 119
    		wdp->word = savestr(fp->word);
  120. 120
    		fp = fp->next;
  121. 121
    	} while (wdp->word[0] != '\n');
  122. 122
    	hp->prev = wdp;
  123. 123
    }
  124. 124
  125. 125
    freelex(vp)
  126. 126
    	register struct wordent *vp;
  127. 127
    {
  128. 128
    	register struct wordent *fp;
  129. 129
  130. 130
    	while (vp->next != vp) {
  131. 131
    		fp = vp->next;
  132. 132
    		vp->next = fp->next;
  133. 133
    		xfree(fp->word);
  134. 134
    		xfree(fp);
  135. 135
    	}
  136. 136
    	vp->prev = vp;
  137. 137
    }
  138. 138
  139. 139
    char	*WORDMETA =	"# '`\"\t;&<>()|\n";
  140. 140
  141. 141
    char *
  142. 142
    word()
  143. 143
    {
  144. 144
    	register char c, c1;
  145. 145
    	register char *wp;
  146. 146
    	char wbuf[BUFSIZ];
  147. 147
    	register bool dolflg;
  148. 148
    	register int i;
  149. 149
  150. 150
    	wp = wbuf;
  151. 151
    	i = BUFSIZ - 4;
  152. 152
    loop:
  153. 153
    	c = getC(DOALL);
  154. 154
    	switch (c) {
  155. 155
  156. 156
    	case ' ':
  157. 157
    	case '\t':
  158. 158
    		goto loop;
  159. 159
  160. 160
    	case '`':
  161. 161
    	case '\'':
  162. 162
    	case '"':
  163. 163
    		*wp++ = c, --i, c1 = c;
  164. 164
    		dolflg = c == '"' ? DOALL : DOEXCL;
  165. 165
    		for (;;) {
  166. 166
    			c = getC(dolflg);
  167. 167
    			if (c == c1)
  168. 168
    				break;
  169. 169
    			if (c == '\n') {
  170. 170
    				seterrc("Unmatched ", c1);
  171. 171
    				ungetC(c);
  172. 172
    				goto ret;
  173. 173
    			}
  174. 174
    			if (c == '\\') {
  175. 175
    				c = getC(0);
  176. 176
    				if (c == '!')
  177. 177
    					c |= QUOTE;
  178. 178
    				else {
  179. 179
    					if (c == '\n' && c1 != '`')
  180. 180
    						c |= QUOTE;
  181. 181
    					ungetC(c), c = '\\';
  182. 182
    				}
  183. 183
    			}
  184. 184
    			if (--i <= 0)
  185. 185
    				goto toochars;
  186. 186
    			*wp++ = c;
  187. 187
    		}
  188. 188
    		*wp++ = c, --i;
  189. 189
    		goto pack;
  190. 190
  191. 191
    	case '&':
  192. 192
    	case '|':
  193. 193
    	case '<':
  194. 194
    	case '>':
  195. 195
    		*wp++ = c;
  196. 196
    		c1 = getC(DOALL);
  197. 197
    		if (c1 == c)
  198. 198
    			*wp++ = c1;
  199. 199
    		else
  200. 200
    			ungetC(c1);
  201. 201
    		goto ret;
  202. 202
  203. 203
    	case '#':
  204. 204
    		if (intty)
  205. 205
    			break;
  206. 206
    		if (wp != wbuf) {
  207. 207
    			ungetC(c);
  208. 208
    			goto ret;
  209. 209
    		}
  210. 210
    		c = 0;
  211. 211
    		do {
  212. 212
    			c1 = c;
  213. 213
    			c = getC(0);
  214. 214
    		} while (c != '\n');
  215. 215
    		if (c1 == '\\')
  216. 216
    			goto loop;
  217. 217
    		/* fall into ... */
  218. 218
  219. 219
    	case ';':
  220. 220
    	case '(':
  221. 221
    	case ')':
  222. 222
    	case '\n':
  223. 223
    		*wp++ = c;
  224. 224
    		goto ret;
  225. 225
  226. 226
    casebksl:
  227. 227
    	case '\\':
  228. 228
    		c = getC(0);
  229. 229
    		if (c == '\n') {
  230. 230
    			if (onelflg == 1)
  231. 231
    				onelflg = 2;
  232. 232
    			goto loop;
  233. 233
    		}
  234. 234
    		if (c != '!')
  235. 235
    			*wp++ = '\\', --i;
  236. 236
    		c |= QUOTE;
  237. 237
    		break;
  238. 238
    	}
  239. 239
    	ungetC(c);
  240. 240
    pack:
  241. 241
    	for (;;) {
  242. 242
    		c = getC(DOALL);
  243. 243
    		if (c == '\\') {
  244. 244
    			c = getC(0);
  245. 245
    			if (c == '\n') {
  246. 246
    				if (onelflg == 1)
  247. 247
    					onelflg = 2;
  248. 248
    				goto ret;
  249. 249
    			}
  250. 250
    			if (c != '!')
  251. 251
    				*wp++ = '\\', --i;
  252. 252
    			c |= QUOTE;
  253. 253
    		}
  254. 254
    		if (any(c, WORDMETA + intty)) {
  255. 255
    			ungetC(c);
  256. 256
    			if (any(c, "\"'`"))
  257. 257
    				goto loop;
  258. 258
    			goto ret;
  259. 259
    		}
  260. 260
    		if (--i <= 0)
  261. 261
    			goto toochars;
  262. 262
    		*wp++ = c;
  263. 263
    	}
  264. 264
    toochars:
  265. 265
    	seterr("Word too long");
  266. 266
    	wp = &wbuf[1];
  267. 267
    ret:
  268. 268
    	*wp = 0;
  269. 269
    	return (savestr(wbuf));
  270. 270
    }
  271. 271
  272. 272
    getC(flag)
  273. 273
    	register int flag;
  274. 274
    {
  275. 275
    	register char c;
  276. 276
  277. 277
    top:
  278. 278
    	if (c = peekc) {
  279. 279
    		peekc = 0;
  280. 280
    		return (c);
  281. 281
    	}
  282. 282
    	if (lap) {
  283. 283
    		c = *lap++;
  284. 284
    		if (c == 0) {
  285. 285
    			lap = 0;
  286. 286
    			goto top;
  287. 287
    		}
  288. 288
    		if (any(c, WORDMETA + intty))
  289. 289
    			c |= QUOTE;
  290. 290
    		return (c);
  291. 291
    	}
  292. 292
    	if (c = peekd) {
  293. 293
    		peekd = 0;
  294. 294
    		return (c);
  295. 295
    	}
  296. 296
    	if (exclp) {
  297. 297
    		if (c = *exclp++)
  298. 298
    			return (c);
  299. 299
    		if (exclnxt && --exclc >= 0) {
  300. 300
    			exclnxt = exclnxt->next;
  301. 301
    			setexclp(exclnxt->word);
  302. 302
    			return (' ');
  303. 303
    		}
  304. 304
    		exclp = 0;
  305. 305
    		exclnxt = 0;
  306. 306
    	}
  307. 307
    	if (exclnxt) {
  308. 308
    		exclnxt = exclnxt->next;
  309. 309
    		if (--exclc < 0)
  310. 310
    			exclnxt = 0;
  311. 311
    		else
  312. 312
    			setexclp(exclnxt->word);
  313. 313
    		goto top;
  314. 314
    	}
  315. 315
    	c = readc(0);
  316. 316
    	if (c == '$' && (flag & DODOL)) {
  317. 317
    		getdol();
  318. 318
    		goto top;
  319. 319
    	}
  320. 320
    	if (c == '!' && (flag & DOEXCL)) {
  321. 321
    		getexcl(0);
  322. 322
    		goto top;
  323. 323
    	}
  324. 324
    	return (c);
  325. 325
    }
  326. 326
  327. 327
    getdol()
  328. 328
    {
  329. 329
    	register char *np;
  330. 330
    	char name[40];
  331. 331
    	register int c;
  332. 332
    	int sc;
  333. 333
    	bool special = 0;
  334. 334
  335. 335
    	np = name, *np++ = '$';
  336. 336
    	c = sc = getC(DOEXCL);
  337. 337
    	if (any(c, "\t \n")) {
  338. 338
    		ungetD(c);
  339. 339
    		ungetC('$' | QUOTE);
  340. 340
    		return;
  341. 341
    	}
  342. 342
    	if (c == '{')
  343. 343
    		*np++ = c, c = getC(DOEXCL);
  344. 344
    	if (c == '#' || c == '?')
  345. 345
    		special++, *np++ = c, c = getC(DOEXCL);
  346. 346
    	*np++ = c;
  347. 347
    	switch (c) {
  348. 348
  349. 349
    	case '$':
  350. 350
    		if (special)
  351. 351
    			goto vsyn;
  352. 352
    		goto ret;
  353. 353
  354. 354
    	case '\n':
  355. 355
    		ungetD(c);
  356. 356
    		np--;
  357. 357
    		goto vsyn;
  358. 358
  359. 359
    	case '*':
  360. 360
    		if (special)
  361. 361
    			goto vsyn;
  362. 362
    		goto ret;
  363. 363
  364. 364
    	default:
  365. 365
    		if (digit(c)) {
  366. 366
    /*
  367. 367
     * let $?0 pass for now
  368. 368
    			if (special)
  369. 369
    				goto vsyn;
  370. 370
    */
  371. 371
    			while (digit(c = getC(DOEXCL))) {
  372. 372
    				if (np < &name[sizeof name / 2])
  373. 373
    					*np++ = c;
  374. 374
    			}
  375. 375
    		} else if (letter(c))
  376. 376
    			while (letter(c = getC(DOEXCL))) {
  377. 377
    				if (np < &name[sizeof name / 2])
  378. 378
    					*np++ = c;
  379. 379
    			}
  380. 380
    		else
  381. 381
    			goto vsyn;
  382. 382
    	}
  383. 383
    	if (c == '[') {
  384. 384
    		*np++ = c;
  385. 385
    		do {
  386. 386
    			c = getC(DOEXCL);
  387. 387
    			if (c == '\n') {
  388. 388
    				ungetD(c);
  389. 389
    				np--;
  390. 390
    				goto vsyn;
  391. 391
    			}
  392. 392
    			if (np >= &name[sizeof name - 8])
  393. 393
    				goto vsyn;
  394. 394
    			*np++ = c;
  395. 395
    		} while (c != ']');
  396. 396
    		c = getC(DOEXCL);
  397. 397
    	}
  398. 398
    	if (c == ':') {
  399. 399
    		*np++ = c, c = getC(DOEXCL);
  400. 400
    		if (c == 'g')
  401. 401
    			*np++ = c, c = getC(DOEXCL);
  402. 402
    		*np++ = c;
  403. 403
    		if (!any(c, "htrqx"))
  404. 404
    			goto vsyn;
  405. 405
    	} else
  406. 406
    		ungetD(c);
  407. 407
    	if (sc == '{') {
  408. 408
    		c = getC(DOEXCL);
  409. 409
    		if (c != '}') {
  410. 410
    			ungetC(c);
  411. 411
    			goto vsyn;
  412. 412
    		}
  413. 413
    		*np++ = c;
  414. 414
    	}
  415. 415
    ret:
  416. 416
    	*np = 0;
  417. 417
    	addla(name);
  418. 418
    	return;
  419. 419
  420. 420
    vsyn:
  421. 421
    	seterr("Variable syntax");
  422. 422
    	goto ret;
  423. 423
    }
  424. 424
  425. 425
    addla(cp)
  426. 426
    	char *cp;
  427. 427
    {
  428. 428
    	char buf[BUFSIZ];
  429. 429
  430. 430
    	if (lap != 0 && strlen(cp) + strlen(lap) >= BUFSIZ - 4) {
  431. 431
    		seterr("Expansion buf ovflo");
  432. 432
    		return;
  433. 433
    	}
  434. 434
    	if (lap)
  435. 435
    		strcpy(buf, lap);
  436. 436
    	strcpy(labuf, cp);
  437. 437
    	if (lap)
  438. 438
    		strcat(labuf, buf);
  439. 439
    	lap = labuf;
  440. 440
    }
  441. 441
  442. 442
    char	lhsb[32];
  443. 443
    char	slhs[32];
  444. 444
    char	rhsb[64];
  445. 445
    int	quesarg;
  446. 446
  447. 447
    getexcl(sc)
  448. 448
    	char sc;
  449. 449
    {
  450. 450
    	register struct wordent *hp, *ip;
  451. 451
    	int left, right, dol;
  452. 452
    	register int c;
  453. 453
  454. 454
    	if (sc == 0) {
  455. 455
    		sc = getC(0);
  456. 456
    		if (sc != '{') {
  457. 457
    			ungetC(sc);
  458. 458
    			sc = 0;
  459. 459
    		}
  460. 460
    	}
  461. 461
    	quesarg = -1;
  462. 462
    	lastev = eventno;
  463. 463
    	hp = gethent(sc);
  464. 464
    	if (hp == 0)
  465. 465
    		return;
  466. 466
    	hadhist = 1;
  467. 467
    	dol = 0;
  468. 468
    	if (hp == alhistp)
  469. 469
    		for (ip = hp->next->next; ip != alhistt; ip = ip->next)
  470. 470
    			dol++;
  471. 471
    	else
  472. 472
    		for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
  473. 473
    			dol++;
  474. 474
    	left = 0, right = dol;
  475. 475
    	if (sc == '^') {
  476. 476
    		ungetC('s'), unreadc('^'), c = ':';
  477. 477
    		goto subst;
  478. 478
    	}
  479. 479
    	c = getC(0);
  480. 480
    	if (!any(c, ":^$*-%"))
  481. 481
    		goto subst;
  482. 482
    	left = right = -1;
  483. 483
    	if (c == ':') {
  484. 484
    		c = getC(0);
  485. 485
    		unreadc(c);
  486. 486
    		if (letter(c) || c == '&') {
  487. 487
    			c = ':';
  488. 488
    			left = 0, right = dol;
  489. 489
    			goto subst;
  490. 490
    		}
  491. 491
    	} else
  492. 492
    		ungetC(c);
  493. 493
    	if (!getsel(&left, &right, dol))
  494. 494
    		return;
  495. 495
    	c = getC(0);
  496. 496
    	if (c == '*')
  497. 497
    		ungetC(c), c = '-';
  498. 498
    	if (c == '-') {
  499. 499
    		if (!getsel(&left, &right, dol))
  500. 500
    			return;
  501. 501
    		c = getC(0);
  502. 502
    	}
  503. 503
    subst:
  504. 504
    	exclc = right - left + 1;
  505. 505
    	while (--left >= 0)
  506. 506
    		hp = hp->next;
  507. 507
    	if (sc == '^' || c == ':') {
  508. 508
    		do {
  509. 509
    			hp = getsub(hp);
  510. 510
    			c = getC(0);
  511. 511
    		} while (c == ':');
  512. 512
    	}
  513. 513
    	unreadc(c);
  514. 514
    	if (sc == '{') {
  515. 515
    		c = getC(0);
  516. 516
    		if (c != '}')
  517. 517
    			seterr("Bad ! form");
  518. 518
    	}
  519. 519
    	exclnxt = hp;
  520. 520
    }
  521. 521
  522. 522
    struct wordent *
  523. 523
    getsub(en)
  524. 524
    	struct wordent *en;
  525. 525
    {
  526. 526
    	register char *cp;
  527. 527
    	int delim;
  528. 528
    	register int c;
  529. 529
    	int sc;
  530. 530
    	bool global = 0;
  531. 531
    	char orhsb[sizeof rhsb];
  532. 532
  533. 533
    	exclnxt = 0;
  534. 534
    	sc = c = getC(0);
  535. 535
    	if (c == 'g')
  536. 536
    		global++, c = getC(0);
  537. 537
    	switch (c) {
  538. 538
  539. 539
    	case 'p':
  540. 540
    		justpr++;
  541. 541
    		goto ret;
  542. 542
  543. 543
    	case 'x':
  544. 544
    	case 'q':
  545. 545
    		global++;
  546. 546
    		/* fall into ... */
  547. 547
  548. 548
    	case 'h':
  549. 549
    	case 'r':
  550. 550
    	case 't':
  551. 551
    		break;
  552. 552
  553. 553
    	case '&':
  554. 554
    		if (slhs[0] == 0) {
  555. 555
    			seterr("No prev sub");
  556. 556
    			goto ret;
  557. 557
    		}
  558. 558
    		strcpy(lhsb, slhs);
  559. 559
    		break;
  560. 560
  561. 561
    /*
  562. 562
    	case '~':
  563. 563
    		if (lhsb[0] == 0)
  564. 564
    			goto badlhs;
  565. 565
    		break;
  566. 566
    */
  567. 567
  568. 568
    	case 's':
  569. 569
    		delim = getC(0);
  570. 570
    		if (letter(delim) || digit(delim) || any(delim, " \t\n")) {
  571. 571
    			unreadc(delim);
  572. 572
    bads:
  573. 573
    			lhsb[0] = 0;
  574. 574
    			seterr("Bad substitute");
  575. 575
    			goto ret;
  576. 576
    		}
  577. 577
    		cp = lhsb;
  578. 578
    		for (;;) {
  579. 579
    			c = getC(0);
  580. 580
    			if (c == '\n') {
  581. 581
    				unreadc(c);
  582. 582
    				goto bads;
  583. 583
    			}
  584. 584
    			if (c == delim)
  585. 585
    				break;
  586. 586
    			if (cp > &lhsb[sizeof lhsb - 2])
  587. 587
    				goto bads;
  588. 588
    			if (c == '\\') {
  589. 589
    				c = getC(0);
  590. 590
    				if (c != delim && c != '\\')
  591. 591
    					*cp++ = '\\';
  592. 592
    			}
  593. 593
    			*cp++ = c;
  594. 594
    		}
  595. 595
    		if (cp != lhsb)
  596. 596
    			*cp++ = 0;
  597. 597
    		else if (lhsb[0] == 0) {
  598. 598
    badlhs:
  599. 599
    			seterr("No prev lhs");
  600. 600
    			goto ret;
  601. 601
    		}
  602. 602
    		cp = rhsb;
  603. 603
    		strcpy(orhsb, cp);
  604. 604
    		for (;;) {
  605. 605
    			c = getC(0);
  606. 606
    			if (c == '\n') {
  607. 607
    				unreadc(c);
  608. 608
    				break;
  609. 609
    			}
  610. 610
    			if (c == delim)
  611. 611
    				break;
  612. 612
    /*
  613. 613
    			if (c == '~') {
  614. 614
    				if (&cp[strlen(orhsb)] > &rhsb[sizeof rhsb - 2])
  615. 615
    					goto toorhs;
  616. 616
    				cp = strend(strcpy(cp, orhsb));
  617. 617
    				continue;
  618. 618
    			}
  619. 619
    */
  620. 620
    			if (cp > &rhsb[sizeof rhsb - 2]) {
  621. 621
    toorhs:
  622. 622
    				seterr("Rhs too long");
  623. 623
    				goto ret;
  624. 624
    			}
  625. 625
    			if (c == '\\') {
  626. 626
    				c = getC(0);
  627. 627
    				if (c != delim /* && c != '~' */)
  628. 628
    					*cp++ = '\\';
  629. 629
    			}
  630. 630
    			*cp++ = c;
  631. 631
    		}
  632. 632
    		*cp++ = 0;
  633. 633
    		break;
  634. 634
  635. 635
    	default:
  636. 636
    		if (c == '\n')
  637. 637
    			unreadc(c);
  638. 638
    		seterrc("Bad ! modifier: ", c);
  639. 639
    		goto ret;
  640. 640
    	}
  641. 641
    	strcpy(slhs, lhsb);
  642. 642
    	if (exclc)
  643. 643
    		en = dosub(sc, en, global);
  644. 644
    ret:
  645. 645
    	return (en);
  646. 646
    }
  647. 647
  648. 648
    struct wordent *
  649. 649
    dosub(sc, en, global)
  650. 650
    	int sc;
  651. 651
    	struct wordent *en;
  652. 652
    	bool global;
  653. 653
    {
  654. 654
    	struct wordent lex;
  655. 655
    	bool didsub = 0;
  656. 656
    	struct wordent *hp = &lex;
  657. 657
    	register struct wordent *wdp;
  658. 658
    	register int i = exclc;
  659. 659
  660. 660
    	wdp = hp;
  661. 661
    	while (--i >= 0) {
  662. 662
    		register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
  663. 663
  664. 664
    		new->prev = wdp;
  665. 665
    		new->next = hp;
  666. 666
    		wdp->next = new;
  667. 667
    		wdp = new;
  668. 668
    		en = en->next;
  669. 669
    		wdp->word = global || didsub == 0 ?
  670. 670
    		    subword(en->word, sc, &didsub) : savestr(en->word);
  671. 671
    	}
  672. 672
    	if (didsub == 0)
  673. 673
    		seterr("Modifier failed");
  674. 674
    	hp->prev = wdp;
  675. 675
    	return (&enthist(-1000, &lex, 0)->Hlex);
  676. 676
    }
  677. 677
  678. 678
    char *
  679. 679
    subword(cp, type, adid)
  680. 680
    	char *cp;
  681. 681
    	int type;
  682. 682
    	bool *adid;
  683. 683
    {
  684. 684
    	char wbuf[BUFSIZ];
  685. 685
    	register char *wp, *mp, *np;
  686. 686
    	register int i;
  687. 687
  688. 688
    	switch (type) {
  689. 689
  690. 690
    	case 'r':
  691. 691
    	case 'h':
  692. 692
    	case 't':
  693. 693
    	case 'q':
  694. 694
    	case 'x':
  695. 695
    		wp = domod(cp, type);
  696. 696
    		if (wp == 0)
  697. 697
    			return (savestr(cp));
  698. 698
    		*adid = 1;
  699. 699
    		return (wp);
  700. 700
  701. 701
    	default:
  702. 702
    		wp = wbuf;
  703. 703
    		i = BUFSIZ - 4;
  704. 704
    		for (mp = cp; *mp; mp++)
  705. 705
    			if (matchs(mp, lhsb)) {
  706. 706
    				for (np = cp; np < mp;)
  707. 707
    					*wp++ = *np++, --i;
  708. 708
    				for (np = rhsb; *np; np++) switch (*np) {
  709. 709
  710. 710
    				case '\\':
  711. 711
    					if (np[1] == '&')
  712. 712
    						np++;
  713. 713
    					/* fall into ... */
  714. 714
  715. 715
    				default:
  716. 716
    					if (--i < 0)
  717. 717
    						goto ovflo;
  718. 718
    					*wp++ = *np;
  719. 719
    					continue;
  720. 720
  721. 721
    				case '&':
  722. 722
    					i -= strlen(lhsb);
  723. 723
    					if (i < 0)
  724. 724
    						goto ovflo;
  725. 725
    					*wp = 0;
  726. 726
    					strcat(wp, lhsb);
  727. 727
    					wp = strend(wp);
  728. 728
    					continue;
  729. 729
    				}
  730. 730
    				mp += strlen(lhsb);
  731. 731
    				i -= strlen(mp);
  732. 732
    				if (i < 0) {
  733. 733
    ovflo:
  734. 734
    					seterr("Subst buf ovflo");
  735. 735
    					return ("");
  736. 736
    				}
  737. 737
    				*wp = 0;
  738. 738
    				strcat(wp, mp);
  739. 739
    				*adid = 1;
  740. 740
    				return (savestr(wbuf));
  741. 741
    			}
  742. 742
    		return (savestr(cp));
  743. 743
    	}
  744. 744
    }
  745. 745
  746. 746
    char *
  747. 747
    domod(cp, type)
  748. 748
    	char *cp;
  749. 749
    	int type;
  750. 750
    {
  751. 751
    	register char *wp, *xp;
  752. 752
    	register int c;
  753. 753
  754. 754
    	switch (type) {
  755. 755
  756. 756
    	case 'x':
  757. 757
    	case 'q':
  758. 758
    		wp = savestr(cp);
  759. 759
    		for (xp = wp; c = *xp; xp++)
  760. 760
    			if ((c != ' ' && c != '\t') || type == 'q')
  761. 761
    				*xp |= QUOTE;
  762. 762
    		return (wp);
  763. 763
  764. 764
    	case 'h':
  765. 765
    	case 't':
  766. 766
    		if (!any('/', cp))
  767. 767
    			return (0);
  768. 768
    		wp = strend(cp);
  769. 769
    		while (*--wp != '/')
  770. 770
    			continue;
  771. 771
    		if (type == 'h')
  772. 772
    take:
  773. 773
    			xp = savestr(cp), xp[wp - cp] = 0;
  774. 774
    		else
  775. 775
    			xp = savestr(wp + 1);
  776. 776
    		return (xp);
  777. 777
  778. 778
    	case 'r':
  779. 779
    		wp = strend(cp);
  780. 780
    		for (wp--; wp >= cp && *wp != '.'; wp--)
  781. 781
    			if (*wp == '/')
  782. 782
    				return (0);
  783. 783
    		if (wp < cp)
  784. 784
    			return (0);
  785. 785
    		goto take;
  786. 786
    	}
  787. 787
    	return (0);
  788. 788
    }
  789. 789
  790. 790
    matchs(str, pat)
  791. 791
    	register char *str, *pat;
  792. 792
    {
  793. 793
  794. 794
    	while (*str && *pat && *str == *pat)
  795. 795
    		str++, pat++;
  796. 796
    	return (*pat == 0);
  797. 797
    }
  798. 798
  799. 799
    getsel(al, ar, dol)
  800. 800
    	register int *al, *ar;
  801. 801
    	int dol;
  802. 802
    {
  803. 803
    	register int c = getC(0);
  804. 804
    	register int i;
  805. 805
    	bool first = *al < 0;
  806. 806
  807. 807
    	switch (c) {
  808. 808
  809. 809
    	case '%':
  810. 810
    		if (quesarg == -1)
  811. 811
    			goto bad;
  812. 812
    		if (*al < 0)
  813. 813
    			*al = quesarg;
  814. 814
    		*ar = quesarg;
  815. 815
    		break;
  816. 816
  817. 817
    	case '-':
  818. 818
    		if (*al < 0) {
  819. 819
    			*al = 0;
  820. 820
    			*ar = dol - 1;
  821. 821
    			unreadc(c);
  822. 822
    		}
  823. 823
    		return (1);
  824. 824
  825. 825
    	case '^':
  826. 826
    		if (*al < 0)
  827. 827
    			*al = 1;
  828. 828
    		*ar = 1;
  829. 829
    		break;
  830. 830
  831. 831
    	case '$':
  832. 832
    		if (*al < 0)
  833. 833
    			*al = dol;
  834. 834
    		*ar = dol;
  835. 835
    		break;
  836. 836
  837. 837
    	case '*':
  838. 838
    		if (*al < 0)
  839. 839
    			*al = 1;
  840. 840
    		*ar = dol;
  841. 841
    		if (*ar < *al) {
  842. 842
    			*ar = 0;
  843. 843
    			*al = 1;
  844. 844
    			return (1);
  845. 845
    		}
  846. 846
    		break;
  847. 847
  848. 848
    	default:
  849. 849
    		if (digit(c)) {
  850. 850
    			i = 0;
  851. 851
    			while (digit(c)) {
  852. 852
    				i = i * 10 + c - '0';
  853. 853
    				c = getC(0);
  854. 854
    			}
  855. 855
    			if (i < 0)
  856. 856
    				i = dol + 1;
  857. 857
    			if (*al < 0)
  858. 858
    				*al = i;
  859. 859
    			*ar = i;
  860. 860
    		} else
  861. 861
    			if (*al < 0)
  862. 862
    				*al = 0, *ar = dol;
  863. 863
    			else
  864. 864
    				*ar = dol - 1;
  865. 865
    		unreadc(c);
  866. 866
    		break;
  867. 867
    	}
  868. 868
    	if (first) {
  869. 869
    		c = getC(0);
  870. 870
    		unreadc(c);
  871. 871
    		if (any(c, "-$*"))
  872. 872
    			return (1);
  873. 873
    	}
  874. 874
    	if (*al > *ar || *ar > dol) {
  875. 875
    bad:
  876. 876
    		seterr("Bad ! arg selector");
  877. 877
    		return (0);
  878. 878
    	}
  879. 879
    	return (1);
  880. 880
    }
  881. 881
  882. 882
    struct wordent *
  883. 883
    gethent(sc)
  884. 884
    	int sc;
  885. 885
    {
  886. 886
    	register struct Hist *hp;
  887. 887
    	register char *np;
  888. 888
    	register int c;
  889. 889
    	int event;
  890. 890
    	bool back = 0;
  891. 891
  892. 892
    	c = sc == '^' ? '!' : getC(0);
  893. 893
    	switch (c) {
  894. 894
  895. 895
    	case ':':
  896. 896
    	case '^':
  897. 897
    	case '$':
  898. 898
    	case '*':
  899. 899
    	case '%':
  900. 900
    		ungetC(c);
  901. 901
    		if (lastev == eventno && alhistp)
  902. 902
    			return (alhistp);
  903. 903
    		event = lastev;
  904. 904
    		break;
  905. 905
  906. 906
    	case '!':
  907. 907
    		event = eventno;
  908. 908
    		break;
  909. 909
  910. 910
    	case '-':
  911. 911
    		back = 1;
  912. 912
    		c = getC(0);
  913. 913
    		goto number;
  914. 914
  915. 915
    	default:
  916. 916
    		if (any(c, "(=")) {
  917. 917
    			unreadc(c);
  918. 918
    			ungetC('!');
  919. 919
    			return (0);
  920. 920
    		}
  921. 921
    		if (digit(c))
  922. 922
    			goto number;
  923. 923
    		np = lhsb;
  924. 924
    		while (!any(c, ": \t\\\n}")) {
  925. 925
    			if (np < &lhsb[sizeof lhsb - 2])
  926. 926
    				*np++ = c;
  927. 927
    			c = getC(0);
  928. 928
    		}
  929. 929
    		unreadc(c);
  930. 930
    		if (np == lhsb) {
  931. 931
    			ungetC('!');
  932. 932
    			return (0);
  933. 933
    		}
  934. 934
    		*np++ = 0;
  935. 935
    		hp = findev(lhsb, 0);
  936. 936
    		if (hp)
  937. 937
    			lastev = hp->Hnum;
  938. 938
    		return (&hp->Hlex);
  939. 939
  940. 940
    	case '?':
  941. 941
    		np = lhsb;
  942. 942
    		for (;;) {
  943. 943
    			c = getC(0);
  944. 944
    			if (c == '\n') {
  945. 945
    				unreadc(c);
  946. 946
    				break;
  947. 947
    			}
  948. 948
    			if (c == '?')
  949. 949
    				break;
  950. 950
    			if (np < &lhsb[sizeof lhsb - 2])
  951. 951
    				*np++ = c;
  952. 952
    		}
  953. 953
    		if (np == lhsb) {
  954. 954
    			if (lhsb[0] == 0) {
  955. 955
    				seterr("No prev search");
  956. 956
    				return (0);
  957. 957
    			}
  958. 958
    		} else
  959. 959
    			*np++ = 0;
  960. 960
    		hp = findev(lhsb, 1);
  961. 961
    		if (hp)
  962. 962
    			lastev = hp->Hnum;
  963. 963
    		return (&hp->Hlex);
  964. 964
  965. 965
    	number:
  966. 966
    		event = 0;
  967. 967
    		while (digit(c)) {
  968. 968
    			event = event * 10 + c - '0';
  969. 969
    			c = getC(0);
  970. 970
    		}
  971. 971
    		if (back)
  972. 972
    			event = eventno + (alhistp == 0) - (event ? event : 0);
  973. 973
    		unreadc(c);
  974. 974
    		break;
  975. 975
    	}
  976. 976
    	for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
  977. 977
    		if (hp->Hnum == event) {
  978. 978
    			hp->Href = eventno;
  979. 979
    			lastev = hp->Hnum;
  980. 980
    			return (&hp->Hlex);
  981. 981
    		}
  982. 982
    	np = putn(event);
  983. 983
    	noev(np);
  984. 984
    	return (0);
  985. 985
    }
  986. 986
  987. 987
    struct Hist *
  988. 988
    findev(cp, anyarg)
  989. 989
    	char *cp;
  990. 990
    	bool anyarg;
  991. 991
    {
  992. 992
    	register struct Hist *hp;
  993. 993
  994. 994
    	for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
  995. 995
    		if (matchev(hp, cp, anyarg))
  996. 996
    			return (hp);
  997. 997
    	noev(cp);
  998. 998
    	return (0);
  999. 999
    }
  1000. 1000
  1001. 1001
    noev(cp)
  1002. 1002
    	char *cp;
  1003. 1003
    {
  1004. 1004
  1005. 1005
    	seterr2(cp, ": Event not found");
  1006. 1006
    }
  1007. 1007
  1008. 1008
    matchev(hp, cp, anyarg)
  1009. 1009
    	register struct Hist *hp;
  1010. 1010
    	char *cp;
  1011. 1011
    	bool anyarg;
  1012. 1012
    {
  1013. 1013
    	register char *dp;
  1014. 1014
    	struct wordent *lp = &hp->Hlex;
  1015. 1015
    	int argno = 0;
  1016. 1016
  1017. 1017
    	for (;;) {
  1018. 1018
    		lp = lp->next;
  1019. 1019
    		if (lp->word[0] == '\n')
  1020. 1020
    			return (0);
  1021. 1021
    		for (dp = lp->word; *dp; dp++) {
  1022. 1022
    			if (matchs(dp, cp)) {
  1023. 1023
    				if (anyarg)
  1024. 1024
    					quesarg = argno;
  1025. 1025
    				return (1);
  1026. 1026
    			}
  1027. 1027
    			if (!anyarg)
  1028. 1028
    				return (0);
  1029. 1029
    		}
  1030. 1030
    		argno++;
  1031. 1031
    	}
  1032. 1032
    }
  1033. 1033
  1034. 1034
    setexclp(cp)
  1035. 1035
    	register char *cp;
  1036. 1036
    {
  1037. 1037
  1038. 1038
    	if (cp[0] == '\n')
  1039. 1039
    		return;
  1040. 1040
    	exclp = cp;
  1041. 1041
    }
  1042. 1042
  1043. 1043
    unreadc(c)
  1044. 1044
    	char c;
  1045. 1045
    {
  1046. 1046
  1047. 1047
    	peekread = c;
  1048. 1048
    }
  1049. 1049
  1050. 1050
    readc(wanteof)
  1051. 1051
    	bool wanteof;
  1052. 1052
    {
  1053. 1053
    	register int c;
  1054. 1054
  1055. 1055
    	if (c = peekread) {
  1056. 1056
    		peekread = 0;
  1057. 1057
    		return (c);
  1058. 1058
    	}
  1059. 1059
    top:
  1060. 1060
    	if (alvecp) {
  1061. 1061
    		if (c = *alvecp++)
  1062. 1062
    			return (c);
  1063. 1063
    		if (*alvec) {
  1064. 1064
    			alvecp = *alvec++;
  1065. 1065
    			return (' ');
  1066. 1066
    		}
  1067. 1067
    	}
  1068. 1068
    	if (alvec) {
  1069. 1069
    		if (alvecp = *alvec) {
  1070. 1070
    			alvec++;
  1071. 1071
    			goto top;
  1072. 1072
    		}
  1073. 1073
    		/* Infinite source! */
  1074. 1074
    		return ('\n');
  1075. 1075
    	}
  1076. 1076
    	do {
  1077. 1077
    		if (arginp == (char *) 1 || onelflg == 1) {
  1078. 1078
    			if (wanteof)
  1079. 1079
    				return (-1);
  1080. 1080
    			exitstat();
  1081. 1081
    		}
  1082. 1082
    		if (arginp) {
  1083. 1083
    			if ((c = *arginp++) == 0) {
  1084. 1084
    				arginp = (char *) 1;
  1085. 1085
    				return ('\n');
  1086. 1086
    			}
  1087. 1087
    			return (c);
  1088. 1088
    		}
  1089. 1089
    		c = bgetc();
  1090. 1090
    		if (c < 0) {
  1091. 1091
    #include <sgtty.h>
  1092. 1092
    			struct sgttyb tty;
  1093. 1093
  1094. 1094
    			if (wanteof)
  1095. 1095
    				return (-1);
  1096. 1096
    			/* was isatty but raw with ignoreeof yields problems */
  1097. 1097
    			if (adrof("ignoreeof") && gtty(SHIN, &tty)==0 && (tty.sg_flags & RAW) == 0) {
  1098. 1098
    				if (loginsh)
  1099. 1099
    					printf("\nUse \"logout\" to logout.\n");
  1100. 1100
    				else
  1101. 1101
    					printf("\nUse \"exit\" to leave csh.\n");
  1102. 1102
    				reset();
  1103. 1103
    			}
  1104. 1104
    			doneinp = 1;
  1105. 1105
    			reset();
  1106. 1106
    		}
  1107. 1107
    		if (c == '\n' && onelflg)
  1108. 1108
    			onelflg--;
  1109. 1109
    	} while (c == 0);
  1110. 1110
    	return (c);
  1111. 1111
    }
  1112. 1112
  1113. 1113
    bgetc()
  1114. 1114
    {
  1115. 1115
    	register int buf, off, c;
  1116. 1116
  1117. 1117
    #ifdef TELL
  1118. 1118
    	if (cantell) {
  1119. 1119
    		if (fseekp < fbobp || fseekp > feobp) {
  1120. 1120
    			fbobp = feobp = fseekp;
  1121. 1121
    			lseek(SHIN, fseekp, 0);
  1122. 1122
    		}
  1123. 1123
    		if (fseekp == feobp) {
  1124. 1124
    			fbobp = feobp;
  1125. 1125
    			do
  1126. 1126
    				c = read(SHIN, fbuf[0], BUFSIZ);
  1127. 1127
    			while (c < 0 && errno == EINTR);
  1128. 1128
    			if (c <= 0)
  1129. 1129
    				return (-1);
  1130. 1130
    			feobp += c;
  1131. 1131
    		}
  1132. 1132
    		c = fbuf[0][fseekp - fbobp];
  1133. 1133
    		fseekp++;
  1134. 1134
    		return (c);
  1135. 1135
    	}
  1136. 1136
    #endif
  1137. 1137
    again:
  1138. 1138
    	buf = (int) fseekp / BUFSIZ;
  1139. 1139
    	if (buf >= fblocks) {
  1140. 1140
    		register char **nfbuf = (char **) calloc(fblocks+2, sizeof (char **));
  1141. 1141
  1142. 1142
    		if (fbuf) {
  1143. 1143
    			blkcpy(nfbuf, fbuf);
  1144. 1144
    			xfree(fbuf);
  1145. 1145
    		}
  1146. 1146
    		fbuf = nfbuf;
  1147. 1147
    		fbuf[fblocks] = calloc(BUFSIZ, sizeof (char));
  1148. 1148
    		fblocks++;
  1149. 1149
    		goto again;
  1150. 1150
    	}
  1151. 1151
    	if (fseekp >= feobp) {
  1152. 1152
    		buf = (int) feobp / BUFSIZ;
  1153. 1153
    		off = (int) feobp % BUFSIZ;
  1154. 1154
    		do
  1155. 1155
    			c = read(SHIN, fbuf[buf] + off, BUFSIZ - off);
  1156. 1156
    		while (c < 0 && errno == EINTR);
  1157. 1157
    		if (c <= 0)
  1158. 1158
    			return (-1);
  1159. 1159
    		feobp += c;
  1160. 1160
    		goto again;
  1161. 1161
    	}
  1162. 1162
    	c = fbuf[buf][(int) fseekp % BUFSIZ];
  1163. 1163
    	fseekp++;
  1164. 1164
    	return (c);
  1165. 1165
    }
  1166. 1166
  1167. 1167
    bfree()
  1168. 1168
    {
  1169. 1169
    	register int sb, i;
  1170. 1170
  1171. 1171
    #ifdef TELL
  1172. 1172
    	if (cantell)
  1173. 1173
    		return;
  1174. 1174
    #endif
  1175. 1175
    	if (whyles)
  1176. 1176
    		return;
  1177. 1177
    	sb = (int) (fseekp - 1) / BUFSIZ;
  1178. 1178
    	if (sb > 0) {
  1179. 1179
    		for (i = 0; i < sb; i++)
  1180. 1180
    			xfree(fbuf[i]);
  1181. 1181
    		blkcpy(fbuf, &fbuf[sb]);
  1182. 1182
    		fseekp -= BUFSIZ * sb;
  1183. 1183
    		feobp -= BUFSIZ * sb;
  1184. 1184
    		fblocks -= sb;
  1185. 1185
    	}
  1186. 1186
    }
  1187. 1187
  1188. 1188
    bseek(l)
  1189. 1189
    	long l;
  1190. 1190
    {
  1191. 1191
    	register struct whyle *wp;
  1192. 1192
  1193. 1193
    	fseekp = l;
  1194. 1194
    #ifdef TELL
  1195. 1195
    	if (!cantell) {
  1196. 1196
    #endif
  1197. 1197
    		if (!whyles)
  1198. 1198
    			return;
  1199. 1199
    		for (wp = whyles; wp->w_next; wp = wp->w_next)
  1200. 1200
    			continue;
  1201. 1201
    		if (wp->w_start > l)
  1202. 1202
    			l = wp->w_start;
  1203. 1203
    #ifdef TELL
  1204. 1204
    	}
  1205. 1205
    #endif
  1206. 1206
    }
  1207. 1207
  1208. 1208
    /* any similarity to bell telephone is purely accidental */
  1209. 1209
    long
  1210. 1210
    btell()
  1211. 1211
    {
  1212. 1212
  1213. 1213
    	return (fseekp);
  1214. 1214
    }
  1215. 1215
  1216. 1216
    btoeof()
  1217. 1217
    {
  1218. 1218
  1219. 1219
    	lseek(SHIN, 0l, 2);
  1220. 1220
    	fseekp = feobp;
  1221. 1221
    	wfree();
  1222. 1222
    	bfree();
  1223. 1223
    }
  1224. 1224
  1225. 1225
    #ifdef TELL
  1226. 1226
    settell()
  1227. 1227
    {
  1228. 1228
  1229. 1229
    	cantell = 0;
  1230. 1230
    	if (arginp || onelflg || intty)
  1231. 1231
    		return;
  1232. 1232
    	if (lseek(SHIN, 0l, 1) < 0 || errno == ESPIPE)
  1233. 1233
    		return;
  1234. 1234
    	fbuf = (char **) calloc(2, sizeof (char **));
  1235. 1235
    	fblocks = 1;
  1236. 1236
    	fbuf[0] = calloc(BUFSIZ, sizeof (char));
  1237. 1237
    	fseekp = fbobp = feobp = tell(SHIN);
  1238. 1238
    	cantell = 1;
  1239. 1239
    }
  1240. 1240
    #endif

To the top of this page