Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

534 lines
15 KiB

  1. #define EXT_ID "justify ver 2.02 "##__DATE__##" "##__TIME__
  2. /*
  3. ** Justify Z extension
  4. **
  5. ** History:
  6. ** 12-Sep-1988 mz Made WhenLoaded match declaration
  7. ** 01-Sep-1988 Corrected hang when flush-justifying a line with no
  8. ** spaces.
  9. ** 14-Aug-1988 Corrected right-justification on non-column-1 based
  10. ** lines. Corrected justification over multiple
  11. ** paragraphs.
  12. ** 30-Mar-1988 Extracted from "myext".
  13. **
  14. */
  15. #include <ctype.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include "ext.h"
  19. #ifndef TRUE
  20. #define TRUE -1
  21. #define FALSE 0
  22. #endif
  23. void pascal near DumpLine (char far *, PFILE, COL, COL, LINE, char far *, int);
  24. int pascal near NextLine (char far *, PFILE, LINE, LINE far *, int far *);
  25. flagType pascal near isterm (char);
  26. void pascal near _stat (char *);
  27. #ifdef DEBUG
  28. void pascal near debend (flagType);
  29. void pascal near debhex (long);
  30. void pascal near debmsg (char far *);
  31. #else
  32. #define debend(x)
  33. #define debhex(x)
  34. #define debmsg(x)
  35. #endif
  36. flagType just2space = TRUE;
  37. int justwidth = 79;
  38. /*************************************************************************
  39. **
  40. ** justify
  41. ** justify paragraph(s)
  42. **
  43. ** NOARG: Justify between columns 0 and 78, from the current line to
  44. ** blank line.
  45. ** NULLARG: Justify between current column and 78, from the current line to
  46. ** blank line.
  47. ** LINEARG: Justify between current column and 78, the specified lines.
  48. ** "STREAMARG": Justify between specified columns from current line to blank.
  49. ** (handled by boxarg)
  50. ** BOXARG: justify between specified columns the specified rows
  51. ** TEXTARG: Justify between columns 0 and 78, from the current line to
  52. ** blank line, prepending each resulting line with the textarg.
  53. */
  54. flagType pascal EXTERNAL
  55. justify (
  56. CMDDATA argData,
  57. ARG far *pArg,
  58. flagType fMeta
  59. )
  60. {
  61. int cbLine; /* length of line just read */
  62. char inbuf[512]; /* input buffer */
  63. PFILE pFile; /* file handle */
  64. char far *pText; /* pointer to prepending text */
  65. COL x1; /* justify to left column */
  66. COL x2; /* justify to right columne */
  67. LINE y1; /* start line */
  68. LINE y2; /* end line */
  69. LINE yOut; /* output line */
  70. //
  71. // Unreferenced parameters
  72. //
  73. (void)argData;
  74. _stat(EXT_ID);
  75. switch (pArg->argType) {
  76. case NOARG: /* justify paragraph */
  77. x1 = 0; /* between cols 0... */
  78. x2 = justwidth; /* ...and 79 */
  79. y1 = pArg->arg.noarg.y; /* current line... */
  80. y2 = -1; /* ...to blank line*/
  81. pText = 0; /* there is no text */
  82. break;
  83. case NULLARG: /* justify indented */
  84. x1 = pArg->arg.nullarg.x; /* between cur col... */
  85. x2 = justwidth; /* ...and 79 */
  86. y1 = pArg->arg.nullarg.y; /* current line... */
  87. y2 = -1; /* ...to blank line*/
  88. pText = 0; /* there is no text */
  89. break;
  90. case LINEARG: /* justify line range */
  91. x1 = 0; /* between cols 0... */
  92. x2 = justwidth; /* ...and 79 */
  93. y1 = pArg->arg.linearg.yStart; /* and range of lines */
  94. y2 = pArg->arg.linearg.yEnd;
  95. pText = 0; /* there is no text */
  96. break;
  97. case BOXARG: /* justify box */
  98. x1 = pArg->arg.boxarg.xLeft; /* from left corner... */
  99. x2 = pArg->arg.boxarg.xRight; /* ...to right */
  100. y1 = pArg->arg.boxarg.yTop; /* from top... */
  101. y2 = pArg->arg.boxarg.yBottom; /* ...to bottom */
  102. pText = 0; /* there is no text */
  103. break;
  104. case TEXTARG: /* justify & prepend */
  105. x1 = 0; /* between 0... */
  106. x2 = justwidth; /* ...and 79 */
  107. y1 = pArg->arg.textarg.y; /* current line... */
  108. y2 = -1; /* ...to blank line */
  109. pText = pArg->arg.textarg.pText; /* there IS text */
  110. break;
  111. }
  112. pFile = FileNameToHandle ("", "");
  113. if (y1 == y2) /* if same line, then */
  114. y2 = -1; /* just to blank line */
  115. if (x1 == x2) /* if same column */
  116. x2 = justwidth; /* then just to default */
  117. if (x2 < x1) { /* if bas-ackwards */
  118. x1 = 0; /* revert to default */
  119. x2 = justwidth;
  120. }
  121. /*
  122. ** while we can get data within the specified limits, format each new line
  123. ** and output back to the file.
  124. */
  125. inbuf[0] = 0;
  126. yOut = y1;
  127. while (NextLine(inbuf,pFile,y1,&y2,&cbLine)) {
  128. /*
  129. ** if the line was blank, NextLine returned TRUE becase we're formating a
  130. ** range of text. This means we've reached the end of one paragraph. We dump
  131. ** the text collected so far (if any), and then a blank line.
  132. */
  133. if (cbLine == 0) {
  134. if (inbuf[0]) {
  135. DumpLine(inbuf,pFile,x1,x2,yOut++,pText,0);
  136. y1++;
  137. if (y2 != (LINE)-1)
  138. y2++;
  139. }
  140. DumpLine("",pFile,x1,x2,yOut++,pText,0);/* dump blank line */
  141. y1++;
  142. if (y2 != (LINE)-1)
  143. y2++;
  144. }
  145. else
  146. /*
  147. ** inbuf contains the data collected so far for output. Output one newly
  148. ** formated line at a time until the contents of inbuf are narrower than
  149. ** our output columns.
  150. */
  151. while ((COL)strlen(inbuf) > (x2-x1)) { /* while data to output */
  152. DumpLine(inbuf,pFile,x1,x2,yOut++,pText,fMeta);
  153. y1++; /* line moves with insert*/
  154. if (y2 != (LINE)-1)
  155. y2++;
  156. }
  157. }
  158. /*
  159. ** Dump any partial last line. Then if we were formatting to a blank line,
  160. ** dump out one of those too.;
  161. */
  162. if (inbuf[0])
  163. DumpLine (inbuf,pFile,x1,x2,yOut++,pText,0); /* dump last line */
  164. if (y2 == -1)
  165. DumpLine (NULL,pFile,x1,x2,yOut++,pText,0); /* dump blank line */
  166. return TRUE;
  167. /* end justify */}
  168. /*** NextLine - Get next line from file
  169. *
  170. * Get next line from file, remove leading and trailing spaces, and append
  171. * it to the input buffer. Each line is deleted from the file as it is
  172. * read in. This means that the target terminator, (*py2), is decremented
  173. * by one for each line read in.
  174. *
  175. * Input:
  176. * pBuf = pointer to input buffer
  177. * pFile = file pointer
  178. * y1 = line # to read
  179. * py2 = pointer to line # to stop at (updated)
  180. * pcbLine = pointer to place to put the count of bytes read
  181. *
  182. * Output:
  183. * Returns TRUE on a line being read & more reformatting should occurr.
  184. *
  185. *************************************************************************/
  186. int pascal near NextLine (
  187. char far *pBuf, /* input buffer */
  188. PFILE pFile, /* file pointer */
  189. LINE y1, /* line # to read */
  190. LINE far *py2, /* line # to stop at */
  191. int far *pcbLine /* loc to place bytes read*/
  192. ) {
  193. flagType fRet = TRUE;
  194. char far *pT; /* working pointer */
  195. char workbuf[512]; /* working buffer */
  196. *pcbLine = 0;
  197. workbuf[0] = 0;
  198. /*
  199. ** If asked for line that is not in file, we're done.
  200. */
  201. if (y1 >= FileLength(pFile))
  202. return FALSE;
  203. /*
  204. ** if current line past range, (and range is not "-1"), then we're done.
  205. */
  206. if ((*py2 != (LINE)-1) && (y1 > *py2))
  207. return FALSE;
  208. /*
  209. ** Get the next line in the file & remove it.
  210. */
  211. *pcbLine = GetLine(y1, workbuf, pFile);
  212. DelLine(pFile, y1, y1);
  213. if (*py2 == 0)
  214. fRet = FALSE;
  215. else if (*py2 != (LINE)-1)
  216. (*py2)--;
  217. /*
  218. ** If the line is blank, and the range is "-1", we're done.
  219. */
  220. if (!*pcbLine && (*py2 == -1))
  221. return FALSE;
  222. /*
  223. ** strip leading spaces in newly input line
  224. */
  225. pT = workbuf; /* point into line */
  226. while (*pT == ' ')
  227. pT++; /* skip leading spaces */
  228. /*
  229. ** If existing buffer is non-empty, append a space & set pointer to end
  230. */
  231. if (strlen(pBuf)) { /* if non-null string */
  232. pBuf += strlen(pBuf); /* point to null */
  233. *pBuf++ = ' '; /* append space */
  234. if (isterm(*(pBuf-2))) /* if sentence term... */
  235. *pBuf++ = ' '; /* append another */
  236. }
  237. /*
  238. ** append new line, but compress multiple spaces into one
  239. */
  240. while (*pT) { /* copy line over */
  241. if (isterm(*pT)) /* if sentence term... */
  242. if (*(pT+1) == ' ') { /* ...space */
  243. *pBuf++ = *pT++; /* copy period */
  244. *pBuf++ = *pT; /* copy space */
  245. }
  246. if ((*pBuf++ = *pT++) == ' ' ) /* copy a char */
  247. while (*pT == ' ') pT++; /* skip multiple spaces */
  248. }
  249. if (*(pBuf-1) == ' ') /* if a trailing space */
  250. pBuf--; /* remove it */
  251. *pBuf = 0;
  252. return fRet;
  253. /* end NextLine */}
  254. /*** DumpLine - Dump one line of text to the file
  255. *
  256. * Dump one line of text to the file. Prepend any required text or spaces,
  257. * and perform word break/cut at right hand column.
  258. *
  259. * Input:
  260. * pBuf = Pointer to the buffer containing data to output. If NULL, pText
  261. * will not be prepended to output text.
  262. * pFile
  263. * x1
  264. * x2
  265. * yOut
  266. * pText
  267. * fFlush
  268. *
  269. * Output:
  270. * Returns .....
  271. *
  272. * Exceptions:
  273. *
  274. * Notes:
  275. *
  276. *************************************************************************/
  277. void pascal near DumpLine (
  278. char far *pBuf, /* data to output */
  279. PFILE pFile, /* file to output to */
  280. COL x1, /* left-hand column */
  281. COL x2, /* right-hand column */
  282. LINE yOut, /* line to output to */
  283. char far *pText, /* text to prepend */
  284. int fFlush /* flush both sides */
  285. ) {
  286. int i;
  287. char far *pT;
  288. char far *pT2;
  289. char workbuf[512]; /* working buffer */
  290. char flushbuf[512]; /* working buffer */
  291. char fSpace; /* space seen flag */
  292. /*
  293. ** Start by prepending any text, and then filling out to the left hand column
  294. ** to justify to.
  295. */
  296. workbuf[0] = 0; /* start with null */
  297. if (pText && pBuf)
  298. strcpy(workbuf,pText); /* if starting with text*/
  299. i = strlen(workbuf); /* length of line-so-far*/
  300. while (i++ < x1)
  301. strcat(workbuf," "); /* fill out with spaces */
  302. /*
  303. ** Append the data to be output, and then starting at the right column, scan
  304. ** back for a space to break at. If one is not found before the left hand
  305. ** column, then break at the right hand column. Copy any line left over back
  306. ** to the passed in buffer
  307. */
  308. if (pBuf) {
  309. strcat(workbuf,pBuf); /* get total line */
  310. *pBuf = 0; /* empty input buffer */
  311. }
  312. if ((COL)strlen(workbuf) > x2) { /* if we need to cut */
  313. pT = &workbuf[x2]; /* point at potential cut*/
  314. while ((pT > (char far *)&workbuf[0]) && (*pT != ' ')) pT--; /* back up to space*/
  315. if (pT <= (char far *)&workbuf[x1]) { /* if none found in range*/
  316. if (pBuf)
  317. strcpy(pBuf,&workbuf[x2]); /* copy remainder of line*/
  318. workbuf[x2] = 0; /* and terminate this one*/
  319. }
  320. else {
  321. while (*++pT == ' '); /* Skip leading spaces */
  322. if (pBuf)
  323. strcpy(pBuf,pT); /* copy remainder of line*/
  324. *pT = 0; /* and terminate this one*/
  325. }
  326. }
  327. /*
  328. ** This code is invoked when the user wants to justify both right and left
  329. ** sides of his text. We determine how many spaces we need to add, and scan
  330. ** through and add one space to each run of spaces until we've added enough
  331. */
  332. if (fFlush) { /* right & left justify?*/
  333. if ((LONG_PTR) (pT = workbuf + strlen(workbuf) - 1) > 0)
  334. while (*pT == ' ')
  335. *pT-- = 0;
  336. if (strchr(workbuf,' ')) {
  337. while ((i = x2 - strlen(workbuf)) > 0) {/* count of spaces to add */
  338. strcpy(flushbuf,workbuf); /* start with unmodified*/
  339. pT = workbuf + x1;
  340. pT2 = flushbuf + x1; /* skip fixed part */
  341. fSpace = FALSE; /* assume no spaces */
  342. while (*pT) { /* while data to copy */
  343. if ((*pT == ' ') && i) { /* time to insert a space*/
  344. fSpace = TRUE; /* we've seen a space */
  345. *pT2++ = ' ';
  346. i--;
  347. while (*pT == ' ')
  348. *pT2++ = *pT++; /* copy run of spaces */
  349. }
  350. if (*pT)
  351. *pT2++ = *pT++; /* copy line */
  352. else if (!fSpace)
  353. break; /* no embedded spaces */
  354. }
  355. *pT2 = 0;
  356. strcpy(workbuf,flushbuf); /* copy back */
  357. if (!fSpace)
  358. break;
  359. }
  360. }
  361. }
  362. CopyLine ((PFILE) NULL, pFile, yOut, yOut, yOut); /* create new line */
  363. PutLine (yOut, workbuf, pFile); /* output line */
  364. /* end DumpLine */}
  365. /*************************************************************************
  366. **
  367. ** isterm
  368. ** returns true/false based on the character being a sentence terminator:
  369. ** one of '.', '?', '!'. Also, always returns false if just2space is off.
  370. */
  371. flagType pascal near isterm(
  372. char c /* character to test */
  373. )
  374. {
  375. return (flagType)(just2space && ((c == '.') || (c == '!') || (c == '?')));
  376. /* end isterm */}
  377. /*
  378. ** switch communication table to Z
  379. */
  380. struct swiDesc swiTable[] = {
  381. { "just2space", toPIF(just2space), SWI_BOOLEAN },
  382. { "justwidth", toPIF(justwidth), SWI_NUMERIC | RADIX10 },
  383. {0, 0, 0}
  384. };
  385. /*
  386. ** command communication table to Z
  387. */
  388. struct cmdDesc cmdTable[] = {
  389. { "justify", justify, 0, MODIFIES | NOARG | NULLARG | LINEARG | BOXARG | TEXTARG },
  390. {0, 0, 0}
  391. };
  392. /*
  393. ** WhenLoaded
  394. ** Executed when these extensions get loaded. Identify self & assign keys.
  395. */
  396. void EXTERNAL WhenLoaded () {
  397. PSWI pwidth;
  398. _stat(EXT_ID);
  399. SetKey ("justify","alt+b");
  400. if (pwidth = FindSwitch("rmargin"))
  401. justwidth = *pwidth->act.ival;
  402. }
  403. /*************************************************************************
  404. **
  405. ** stat - display status line message
  406. **
  407. ** Purpose:
  408. ** Places extension name and message on the status line
  409. **
  410. ** Entry:
  411. ** pszFcn - Pointer to string to be prepended.
  412. **
  413. ** Exit:
  414. ** none
  415. **
  416. ** Exceptions:
  417. ** none
  418. **
  419. */
  420. void pascal near
  421. _stat (
  422. char *pszFcn /* function name */
  423. )
  424. {
  425. buffer buf; /* message buffer */
  426. strcpy(buf,"justify: "); /* start with name */
  427. #ifdef DEBUG
  428. if (strlen(pszFcn) > 71) {
  429. pszFcn+= strlen(pszFcn) - 68;
  430. strcat (buf, "...");
  431. }
  432. #endif
  433. strncat(buf,pszFcn, sizeof(buf)-strlen(buf)); /* append message */
  434. DoMessage (buf); /* display */
  435. }
  436. #ifdef DEBUG
  437. buffer debstring = {0};
  438. extern int delay; /* message delay */
  439. /*** debhex - output long in hex
  440. *
  441. * Display the value of a long in hex
  442. *
  443. * Input:
  444. * lval = long value
  445. *
  446. * Output:
  447. * Returns nothing
  448. *
  449. *************************************************************************/
  450. void pascal near debhex (
  451. long lval
  452. ) {
  453. char lbuf[10];
  454. _ultoa (lval, lbuf, 16);
  455. debmsg (lbuf);
  456. /* end debhex */}
  457. /*** debmsg - piece together debug message
  458. *
  459. * Outputs a the cummulative message formed by successive calls.
  460. *
  461. * Input:
  462. * psz = pointer to message part
  463. *
  464. * Output:
  465. * Returns nothing
  466. *************************************************************************/
  467. void pascal near debmsg (
  468. char far *psz
  469. ) {
  470. _stat (strcat (debstring, psz));
  471. /* end debmsg */}
  472. /*** debend - terminates message accumulation & pauses
  473. *
  474. * Terminates the message accumulation, displays the final message, and
  475. * pauses, either for the pause time, or for a keystroke.
  476. *
  477. * Input:
  478. * fWait = TRUE => wait for a keystroke
  479. *
  480. * Output:
  481. * Returns nothing
  482. *
  483. *************************************************************************/
  484. void pascal near debend (
  485. flagType fWait
  486. ) {
  487. if (fWait) {
  488. _stat (strcat (debstring, " Press a key..."));
  489. ReadChar ();
  490. }
  491. debstring[0] = 0;
  492. /* end debend */}
  493. #endif