Source code of Windows XP (NT5)
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.

407 lines
15 KiB

  1. /*
  2. ** Justify Z extension
  3. **
  4. ** History:
  5. ** 12-Sep-1988 mz Made WhenLoaded match declaration
  6. ** 01-Sep-1988 Corrected hang when flush-justifying a line with no
  7. ** spaces.
  8. ** 14-Aug-1988 Corrected right-justification on non-column-1 based
  9. ** lines. Corrected justification over multiple
  10. ** paragraphs.
  11. ** 30-Mar-1988 Extracted from "myext".
  12. **
  13. */
  14. #include <ctype.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "zext.h"
  18. #ifndef TRUE
  19. #define TRUE -1
  20. #define FALSE 0
  21. #endif
  22. void pascal near DumpLine (char far *, PFILE, COL, COL, LINE, char far *, int);
  23. int pascal near NextLine (char far *, PFILE, LINE, LINE far *, int far *);
  24. flagType pascal near isterm (char);
  25. void pascal near _stat (char *);
  26. flagType just2space = TRUE;
  27. int justwidth = 79;
  28. /*************************************************************************
  29. **
  30. ** justify
  31. ** justify paragraph(s)
  32. **
  33. ** NOARG: Justify between columns 0 and 78, from the current line to
  34. ** blank line.
  35. ** NULLARG: Justify between current column and 78, from the current line to
  36. ** blank line.
  37. ** LINEARG: Justify between current column and 78, the specified lines.
  38. ** "STREAMARG": Justify between specified columns from current line to blank.
  39. ** (handled by boxarg)
  40. ** BOXARG: justify between specified columns the specified rows
  41. ** TEXTARG: Justify between columns 0 and 78, from the current line to
  42. ** blank line, prepending each resulting line with the textarg.
  43. */
  44. flagType pascal EXTERNAL
  45. justify (
  46. CMDDATA argData,
  47. ARG far *pArg,
  48. flagType fMeta
  49. )
  50. {
  51. int cbLine; /* length of line just read */
  52. char inbuf[BUFLEN]; /* input buffer */
  53. PFILE pFile; /* file handle */
  54. char far *pText; /* pointer to prepending text */
  55. COL x1; /* justify to left column */
  56. COL x2; /* justify to right columne */
  57. LINE y1; /* start line */
  58. LINE y2; /* end line */
  59. LINE yOut; /* output line */
  60. //
  61. // Unreferenced parameters
  62. //
  63. (void)argData;
  64. switch (pArg->argType) {
  65. case NOARG: /* justify paragraph */
  66. x1 = 0; /* between cols 0... */
  67. x2 = justwidth; /* ...and 79 */
  68. y1 = pArg->arg.noarg.y; /* current line... */
  69. y2 = -1; /* ...to blank line*/
  70. pText = 0; /* there is no text */
  71. break;
  72. case NULLARG: /* justify indented */
  73. x1 = pArg->arg.nullarg.x; /* between cur col... */
  74. x2 = justwidth; /* ...and 79 */
  75. y1 = pArg->arg.nullarg.y; /* current line... */
  76. y2 = -1; /* ...to blank line*/
  77. pText = 0; /* there is no text */
  78. break;
  79. case LINEARG: /* justify line range */
  80. x1 = 0; /* between cols 0... */
  81. x2 = justwidth; /* ...and 79 */
  82. y1 = pArg->arg.linearg.yStart; /* and range of lines */
  83. y2 = pArg->arg.linearg.yEnd;
  84. pText = 0; /* there is no text */
  85. break;
  86. case BOXARG: /* justify box */
  87. x1 = pArg->arg.boxarg.xLeft; /* from left corner... */
  88. x2 = pArg->arg.boxarg.xRight; /* ...to right */
  89. y1 = pArg->arg.boxarg.yTop; /* from top... */
  90. y2 = pArg->arg.boxarg.yBottom; /* ...to bottom */
  91. pText = 0; /* there is no text */
  92. break;
  93. case TEXTARG: /* justify & prepend */
  94. x1 = 0; /* between 0... */
  95. x2 = justwidth; /* ...and 79 */
  96. y1 = pArg->arg.textarg.y; /* current line... */
  97. y2 = -1; /* ...to blank line */
  98. pText = pArg->arg.textarg.pText; /* there IS text */
  99. break;
  100. }
  101. pFile = FileNameToHandle ("", "");
  102. if (y1 == y2) /* if same line, then */
  103. y2 = -1; /* just to blank line */
  104. if (x1 == x2) /* if same column */
  105. x2 = justwidth; /* then just to default */
  106. if (x2 < x1) { /* if bas-ackwards */
  107. x1 = 0; /* revert to default */
  108. x2 = justwidth;
  109. }
  110. /*
  111. ** while we can get data within the specified limits, format each new line
  112. ** and output back to the file.
  113. */
  114. inbuf[0] = 0;
  115. yOut = y1;
  116. while (NextLine(inbuf,pFile,y1,&y2,&cbLine)) {
  117. /*
  118. ** if the line was blank, NextLine returned TRUE becase we're formating a
  119. ** range of text. This means we've reached the end of one paragraph. We dump
  120. ** the text collected so far (if any), and then a blank line.
  121. */
  122. if (cbLine == 0) {
  123. if (inbuf[0]) {
  124. DumpLine(inbuf,pFile,x1,x2,yOut++,pText,0);
  125. y1++;
  126. if (y2 != (LINE)-1)
  127. y2++;
  128. }
  129. DumpLine("",pFile,x1,x2,yOut++,pText,0);/* dump blank line */
  130. y1++;
  131. if (y2 != (LINE)-1)
  132. y2++;
  133. } else
  134. /*
  135. ** inbuf contains the data collected so far for output. Output one newly
  136. ** formated line at a time until the contents of inbuf are narrower than
  137. ** our output columns.
  138. */
  139. while ((COL)strlen(inbuf) > (x2-x1)) { /* while data to output */
  140. DumpLine(inbuf,pFile,x1,x2,yOut++,pText,fMeta);
  141. y1++; /* line moves with insert*/
  142. if (y2 != (LINE)-1)
  143. y2++;
  144. }
  145. }
  146. /*
  147. ** Dump any partial last line. Then if we were formatting to a blank line,
  148. ** dump out one of those too.;
  149. */
  150. if (inbuf[0])
  151. DumpLine (inbuf,pFile,x1,x2,yOut++,pText,0); /* dump last line */
  152. if (y2 == -1)
  153. DumpLine (NULL,pFile,x1,x2,yOut++,pText,0); /* dump blank line */
  154. return TRUE;
  155. /* end justify */
  156. }
  157. /*** NextLine - Get next line from file
  158. *
  159. * Get next line from file, remove leading and trailing spaces, and append
  160. * it to the input buffer. Each line is deleted from the file as it is
  161. * read in. This means that the target terminator, (*py2), is decremented
  162. * by one for each line read in.
  163. *
  164. * Input:
  165. * pBuf = pointer to input buffer
  166. * pFile = file pointer
  167. * y1 = line # to read
  168. * py2 = pointer to line # to stop at (updated)
  169. * pcbLine = pointer to place to put the count of bytes read
  170. *
  171. * Output:
  172. * Returns TRUE on a line being read & more reformatting should occurr.
  173. *
  174. *************************************************************************/
  175. int pascal near NextLine (
  176. char far *pBuf, /* input buffer */
  177. PFILE pFile, /* file pointer */
  178. LINE y1, /* line # to read */
  179. LINE far *py2, /* line # to stop at */
  180. int far *pcbLine /* loc to place bytes read*/
  181. ) {
  182. flagType fRet = TRUE;
  183. char far *pT; /* working pointer */
  184. char workbuf[BUFLEN]; /* working buffer */
  185. *pcbLine = 0;
  186. workbuf[0] = 0;
  187. /*
  188. ** If asked for line that is not in file, we're done.
  189. */
  190. if (y1 >= FileLength(pFile))
  191. return FALSE;
  192. /*
  193. ** if current line past range, (and range is not "-1"), then we're done.
  194. */
  195. if ((*py2 != (LINE)-1) && (y1 > *py2))
  196. return FALSE;
  197. /*
  198. ** Get the next line in the file & remove it.
  199. */
  200. *pcbLine = GetLine(y1, workbuf, pFile);
  201. DelLine(pFile, y1, y1);
  202. if (*py2 == 0)
  203. fRet = FALSE;
  204. else if (*py2 != (LINE)-1)
  205. (*py2)--;
  206. /*
  207. ** If the line is blank, and the range is "-1", we're done.
  208. */
  209. if (!*pcbLine && (*py2 == -1))
  210. return FALSE;
  211. /*
  212. ** strip leading spaces in newly input line
  213. */
  214. pT = workbuf; /* point into line */
  215. while (*pT == ' ')
  216. pT++; /* skip leading spaces */
  217. /*
  218. ** If existing buffer is non-empty, append a space & set pointer to end
  219. */
  220. if (strlen(pBuf)) { /* if non-null string */
  221. pBuf += strlen(pBuf); /* point to null */
  222. *pBuf++ = ' '; /* append space */
  223. if (isterm(*(pBuf-2))) /* if sentence term... */
  224. *pBuf++ = ' '; /* append another */
  225. }
  226. /*
  227. ** append new line, but compress multiple spaces into one
  228. */
  229. while (*pT) { /* copy line over */
  230. if (isterm(*pT)) /* if sentence term... */
  231. if (*(pT+1) == ' ') { /* ...space */
  232. *pBuf++ = *pT++; /* copy period */
  233. *pBuf++ = *pT; /* copy space */
  234. }
  235. if ((*pBuf++ = *pT++) == ' ' ) /* copy a char */
  236. while (*pT == ' ') pT++; /* skip multiple spaces */
  237. }
  238. if (*(pBuf-1) == ' ') /* if a trailing space */
  239. pBuf--; /* remove it */
  240. *pBuf = 0;
  241. return fRet;
  242. /* end NextLine */}
  243. /*** DumpLine - Dump one line of text to the file
  244. *
  245. * Dump one line of text to the file. Prepend any required text or spaces,
  246. * and perform word break/cut at right hand column.
  247. *
  248. * Input:
  249. * pBuf = Pointer to the buffer containing data to output. If NULL, pText
  250. * will not be prepended to output text.
  251. * pFile
  252. * x1
  253. * x2
  254. * yOut
  255. * pText
  256. * fFlush
  257. *
  258. * Output:
  259. * Returns .....
  260. *
  261. * Exceptions:
  262. *
  263. * Notes:
  264. *
  265. *************************************************************************/
  266. void pascal near DumpLine (
  267. char far *pBuf, /* data to output */
  268. PFILE pFile, /* file to output to */
  269. COL x1, /* left-hand column */
  270. COL x2, /* right-hand column */
  271. LINE yOut, /* line to output to */
  272. char far *pText, /* text to prepend */
  273. int fFlush /* flush both sides */
  274. ) {
  275. int i;
  276. char far *pT;
  277. char far *pT2;
  278. char workbuf[BUFLEN]; /* working buffer */
  279. char flushbuf[BUFLEN]; /* working buffer */
  280. char fSpace; /* space seen flag */
  281. /*
  282. ** Start by prepending any text, and then filling out to the left hand column
  283. ** to justify to.
  284. */
  285. workbuf[0] = 0; /* start with null */
  286. if (pText && pBuf)
  287. strcpy(workbuf,pText); /* if starting with text*/
  288. i = strlen(workbuf); /* length of line-so-far*/
  289. while (i++ < x1)
  290. strcat(workbuf," "); /* fill out with spaces */
  291. /*
  292. ** Append the data to be output, and then starting at the right column, scan
  293. ** back for a space to break at. If one is not found before the left hand
  294. ** column, then break at the right hand column. Copy any line left over back
  295. ** to the passed in buffer
  296. */
  297. if (pBuf) {
  298. strcat(workbuf,pBuf); /* get total line */
  299. *pBuf = 0; /* empty input buffer */
  300. }
  301. if ((COL)strlen(workbuf) > x2) { /* if we need to cut */
  302. pT = &workbuf[x2]; /* point at potential cut*/
  303. while ((pT > (char far *)&workbuf[0]) && (*pT != ' ')) pT--; /* back up to space*/
  304. if (pT <= (char far *)&workbuf[x1]) { /* if none found in range*/
  305. if (pBuf)
  306. strcpy(pBuf,&workbuf[x2]); /* copy remainder of line*/
  307. workbuf[x2] = 0; /* and terminate this one*/
  308. } else {
  309. while (*++pT == ' '); /* Skip leading spaces */
  310. if (pBuf)
  311. strcpy(pBuf,pT); /* copy remainder of line*/
  312. *pT = 0; /* and terminate this one*/
  313. }
  314. }
  315. /*
  316. ** This code is invoked when the user wants to justify both right and left
  317. ** sides of his text. We determine how many spaces we need to add, and scan
  318. ** through and add one space to each run of spaces until we've added enough
  319. */
  320. if (fFlush) { /* right & left justify?*/
  321. pT = workbuf + strlen(workbuf) - 1;
  322. if (pT)
  323. while (*pT == ' ')
  324. *pT-- = 0;
  325. if (strchr(workbuf,' ')) {
  326. while ((i = x2 - strlen(workbuf)) > 0) {/* count of spaces to add */
  327. strcpy(flushbuf,workbuf); /* start with unmodified*/
  328. pT = workbuf + x1;
  329. pT2 = flushbuf + x1; /* skip fixed part */
  330. fSpace = FALSE; /* assume no spaces */
  331. while (*pT) { /* while data to copy */
  332. if ((*pT == ' ') && i) { /* time to insert a space*/
  333. fSpace = TRUE; /* we've seen a space */
  334. *pT2++ = ' ';
  335. i--;
  336. while (*pT == ' ')
  337. *pT2++ = *pT++; /* copy run of spaces */
  338. }
  339. if (*pT)
  340. *pT2++ = *pT++; /* copy line */
  341. else if (!fSpace)
  342. break; /* no embedded spaces */
  343. }
  344. *pT2 = 0;
  345. strcpy(workbuf,flushbuf); /* copy back */
  346. if (!fSpace)
  347. break;
  348. }
  349. }
  350. }
  351. CopyLine ((PFILE) NULL, pFile, yOut, yOut, yOut); /* create new line */
  352. PutLine (yOut, workbuf, pFile); /* output line */
  353. /* end DumpLine */
  354. }
  355. /*************************************************************************
  356. **
  357. ** isterm
  358. ** returns true/false based on the character being a sentence terminator:
  359. ** one of '.', '?', '!'. Also, always returns false if just2space is off.
  360. */
  361. flagType pascal near isterm(
  362. char c /* character to test */
  363. )
  364. {
  365. return (flagType)(just2space && ((c == '.') || (c == '!') || (c == '?')));
  366. /* end isterm */}
  367. /*
  368. ** WhenLoaded
  369. ** Executed when these extensions get loaded. Identify self & assign keys.
  370. */
  371. void justifyWhenLoaded () {
  372. PSWI pwidth;
  373. if (pwidth = FindSwitch("rmargin"))
  374. justwidth = *pwidth->act.ival;
  375. }