PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/block2.c

#
C | 445 lines | 251 code | 59 blank | 135 comment | 65 complexity | d841560f843f5f399891960bf9b9cb97 MD5 | raw file
  1. /*
  2. File: block.c
  3. COPYING: Full text of the copyrights statement at the bottom of the file
  4. Project: WW
  5. Started: 9th July, 1999
  6. Descrition:
  7. Functions concerning text block storage and manipulation
  8. Part II
  9. */
  10. #include "global.h"
  11. #include "l1opt.h"
  12. #include "l1def.h"
  13. #include "nav.h"
  14. #include "memory.h"
  15. #include "undo.h"
  16. #include "block.h"
  17. /* ************************************************************************
  18. Function: Rearrange
  19. Description:
  20. Rearranges a group of lines.
  21. Lines[] contains the # of lines to be placed at what positions.
  22. The permutation algorithm is designed by
  23. Tzvetan Mikov and Stanislav Angelov.
  24. NOTE: pLines is only temporarily modified. The contents remains
  25. the same on exit!
  26. */
  27. void Rearrange(TFile *pFile, int nNumberOfLines, int *pLines)
  28. {
  29. int nStartLine;
  30. int i;
  31. int nDest;
  32. int j;
  33. TLine TempLine;
  34. ASSERT(VALID_PFILE(pFile));
  35. ASSERT(pLines != NULL);
  36. ASSERT(nNumberOfLines > 0);
  37. if (pFile->bReadOnly || pFile->bForceReadOnly)
  38. return;
  39. /*
  40. Determine start line number in pLines
  41. */
  42. nStartLine = INT_MAX;
  43. for (i = 0; i < nNumberOfLines; ++i)
  44. {
  45. if (pLines[i] < nStartLine)
  46. nStartLine = pLines[i];
  47. }
  48. #define MARK INT_MIN
  49. for (i = 0; i < nNumberOfLines; ++i)
  50. pLines[i] |= MARK;
  51. for (i = 0; i < nNumberOfLines; ++i)
  52. {
  53. if ((pLines[i] & MARK) == 0)
  54. continue;
  55. j = i;
  56. /*
  57. As pLines contains line numbers not starting from 0
  58. we subtract and add nStartLine to make the algorithm
  59. works properly
  60. */
  61. nDest = (pLines[j] &= ~MARK) - nStartLine;
  62. while (nDest != i)
  63. {
  64. /*
  65. Swap pFile->pIndex[j] to pFile->pIndex[nDest]
  66. Take care for nStartLine offset.
  67. */
  68. memcpy(&TempLine, &pFile->pIndex[j + nStartLine], sizeof(TLine));
  69. memcpy(&pFile->pIndex[j + nStartLine],
  70. &pFile->pIndex[nDest + nStartLine], sizeof(TLine));
  71. memcpy(&pFile->pIndex[nDest + nStartLine], &TempLine, sizeof(TLine));
  72. j = nDest;
  73. nDest = (pLines[j] &= ~MARK) - nStartLine;
  74. }
  75. }
  76. return;
  77. }
  78. /* ************************************************************************
  79. Function: RevertRearrange
  80. Description:
  81. Exact oposite of Rearrange() function.
  82. */
  83. void RevertRearrange(TFile *pFile, int nNumberOfLines, int *pLines)
  84. {
  85. int nStartLine;
  86. int i;
  87. int nPos;
  88. int nDest;
  89. TLine TempLine;
  90. if (pFile->bReadOnly || pFile->bForceReadOnly)
  91. return;
  92. /*
  93. Determine start line number in pLines
  94. */
  95. nStartLine = INT_MAX;
  96. for (i = 0; i < nNumberOfLines; ++i)
  97. {
  98. if (pLines[i] < nStartLine)
  99. nStartLine = pLines[i];
  100. }
  101. for (i = 0; i < nNumberOfLines; ++i)
  102. pLines[i] |= MARK;
  103. for (i = 0; i < nNumberOfLines; ++i)
  104. {
  105. if ((pLines[i] & MARK) == 0)
  106. continue;
  107. nPos = (pLines[i] &= ~MARK) - nStartLine;
  108. nDest = i;
  109. while (nPos != i)
  110. {
  111. /*
  112. Swap pFile->pIndex[nPos] to pFile->pIndex[nDest]
  113. Take care for nStartLine offset.
  114. */
  115. memcpy(&TempLine, &pFile->pIndex[nPos + nStartLine], sizeof(TLine));
  116. memcpy(&pFile->pIndex[nPos + nStartLine],
  117. &pFile->pIndex[nDest + nStartLine], sizeof(TLine));
  118. memcpy(&pFile->pIndex[nDest + nStartLine], &TempLine, sizeof(TLine));
  119. nPos = (pLines[nDest] &= ~MARK) - nStartLine;
  120. nDest = nPos;
  121. }
  122. }
  123. }
  124. /*
  125. Static variables to pass parameters to compare_lines()
  126. */
  127. static const TFile *_pFile;
  128. static int _nKeyCol;
  129. static int _nKeyColEnd;
  130. /* ************************************************************************
  131. Function: upcase
  132. Description:
  133. Sets a character in upper case depending by bCaseSensitiveSort flag.
  134. */
  135. static char upcase(char c)
  136. {
  137. if (bCaseSensitiveSort)
  138. return c;
  139. return toupper(c);
  140. }
  141. /* ************************************************************************
  142. Function: compare_lines
  143. Description:
  144. Call-back function called by qsort() to compare two lines.
  145. The lines are initialy stored into an integer array. The contents
  146. of the array are line numbers from the file.
  147. The lines are compared in a specific range of characters
  148. starting at offset _nKeyCol and ending at _nKeyColEnd.
  149. NOTE:
  150. There's no guarantee that _nKeyCol position is not falling
  151. at a '\t' TAB characters position. But I suppose this is not
  152. of such a great concern like column block delete/insert operations.
  153. */
  154. static int compare_lines(const void *_l1, const void *_l2)
  155. {
  156. const int *l1 = _l1;
  157. const int *l2 = _l2;
  158. const TLine *pLine1;
  159. const TLine *pLine2;
  160. const char *p1;
  161. const char *p2;
  162. int nCol;
  163. pLine1 = GetLine(_pFile, *l1);
  164. pLine2 = GetLine(_pFile, *l2);
  165. /*
  166. Walk the lines accounting for '\t' TAB characters
  167. and stop if getting to _nKeyCol or last character position.
  168. */
  169. p1 = pLine1->pLine;
  170. nCol = 0;
  171. while (*p1)
  172. {
  173. if (nCol >= _nKeyCol)
  174. break;
  175. if (*p1 == '\t') /* Tab char */
  176. nCol = CalcTab(nCol);
  177. else
  178. nCol++;
  179. ++p1;
  180. }
  181. p2 = pLine2->pLine;
  182. nCol = 0;
  183. while (*p2)
  184. {
  185. if (nCol >= _nKeyCol)
  186. break;
  187. if (*p2 == '\t') /* Tab char */
  188. nCol = CalcTab(nCol);
  189. else
  190. nCol++;
  191. ++p2;
  192. }
  193. /*
  194. Walk through both the lines while:
  195. -- finding difference
  196. -- reaching string end
  197. -- reaching _nKeyColEnd
  198. */
  199. while ((upcase(*p1) - upcase(*p2)) == 0 && *p1 && *p2 && (p1 - pLine1->pLine) < _nKeyColEnd)
  200. ++p1, ++p2;
  201. if (bAscendingSort)
  202. return upcase(*p1) - upcase(*p2);
  203. else
  204. return upcase(*p2) - upcase(*p1);
  205. }
  206. /* ************************************************************************
  207. Function: SortBlockPrim
  208. Description:
  209. Generates an array that represents a sorted sequence of
  210. lines.
  211. nKeyCol == -1 indicates no column block selection to be used as a key
  212. */
  213. static int *SortBlockPrim(TFile *pFile, int nStartLine, int nEndLine,
  214. int nKeyCol, int nKeyColEnd)
  215. {
  216. int *pLineArray;
  217. int i;
  218. int nNumberOfLines;
  219. ASSERT(VALID_PFILE(pFile));
  220. ASSERT(nEndLine - nStartLine > 0);
  221. nNumberOfLines = nEndLine - nStartLine + 1;
  222. pLineArray = alloc(sizeof(int *) * nNumberOfLines);
  223. if (pLineArray == NULL)
  224. return NULL;
  225. for (i = nStartLine; i <= nEndLine; ++i)
  226. pLineArray[i - nStartLine] = i;
  227. /* Pass parameters to compare_lines() */
  228. _pFile = pFile;
  229. _nKeyCol = nKeyCol;
  230. _nKeyColEnd = nKeyColEnd;
  231. if (_nKeyCol == -1)
  232. {
  233. _nKeyCol = 0;
  234. _nKeyColEnd = INT_MAX;
  235. }
  236. qsort(pLineArray, nNumberOfLines, sizeof(int *), compare_lines);
  237. return pLineArray;
  238. }
  239. /* ************************************************************************
  240. Function: SortCurrentBlock
  241. Description:
  242. */
  243. void SortCurrentBlock(TFile *pFile)
  244. {
  245. int *pLineArray;
  246. int nNumberOfLines;
  247. int nEndLine;
  248. int nUndoEntry;
  249. BOOLEAN bResult;
  250. ASSERT(VALID_PFILE(pFile));
  251. if (!pFile->bBlock)
  252. return;
  253. if (pFile->bReadOnly || pFile->bForceReadOnly)
  254. return;
  255. nNumberOfLines = pFile->nEndLine - pFile->nStartLine + 1;
  256. ASSERT(nNumberOfLines > 0);
  257. if (nNumberOfLines == 1)
  258. return; /* single line block */
  259. /*
  260. Pass column block selection to be used as a key (if any selection available)
  261. */
  262. nEndLine = pFile->nEndLine;
  263. if (pFile->blockattr & COLUMN_BLOCK)
  264. pLineArray = SortBlockPrim(pFile,
  265. pFile->nStartLine, nEndLine, pFile->nStartPos, pFile->nEndPos);
  266. else
  267. {
  268. if (pFile->nEndPos == -1)
  269. {
  270. --nEndLine;
  271. --nNumberOfLines;
  272. }
  273. pLineArray = SortBlockPrim(pFile,
  274. pFile->nStartLine, nEndLine, -1, -1);
  275. }
  276. if (pLineArray == NULL)
  277. return;
  278. bResult = TRUE;
  279. nUndoEntry = UNDO_BLOCK_BEGIN();
  280. if (!AddUndoRecord(pFile, acREARRANGE, FALSE))
  281. {
  282. bResult = FALSE;
  283. goto _exit_point;
  284. }
  285. Rearrange(pFile, nNumberOfLines, pLineArray);
  286. RecordUndoData(pFile, pLineArray, pFile->nStartLine, -1, nEndLine, -1);
  287. pFile->bUpdatePage = TRUE;
  288. sprintf(pFile->sMsg, sSorted, nNumberOfLines);
  289. pFile->bChanged = TRUE;
  290. pFile->bRecoveryStored = FALSE;
  291. _exit_point:
  292. UNDO_BLOCK_END(nUndoEntry, bResult);
  293. }
  294. /* ************************************************************************
  295. Function: TrimTrailingBlanks
  296. Description:
  297. Removes trailing blanks of all the lines in the range
  298. nStartLine..nEndLine (nEndLine is not included, at least
  299. one line is processed)
  300. Returns:
  301. TRUE -- lines sucessfully processed, *pnBlanksRemoved contains
  302. the number of blank characters that were removed.
  303. FALSE -- operation failed (no memory)
  304. */
  305. BOOLEAN TrimTrailingBlanks(TFile *pFile, int nStartLine, int nEndLine,
  306. int *pnBlanksRemoved)
  307. {
  308. int i;
  309. int nUndoEntry;
  310. BOOLEAN bResult;
  311. char *p;
  312. char *pLine;
  313. char *pEndOfLine;
  314. ASSERT(VALID_PFILE(pFile));
  315. ASSERT(nStartLine >= 0);
  316. ASSERT(nEndLine <= pFile->nNumberOfLines);
  317. nEndLine = pFile->nEndLine;
  318. if (pFile->nEndPos == -1)
  319. --nEndLine;
  320. ASSERT(nEndLine >= 0);
  321. bResult = TRUE;
  322. nUndoEntry = UNDO_BLOCK_BEGIN();
  323. *pnBlanksRemoved = 0;
  324. for (i = nStartLine; i <= nEndLine; ++i)
  325. {
  326. pLine = GetLineText(pFile, i);
  327. if (pLine[0] == '\0')
  328. continue; /* line is empty */
  329. p = strchr(pLine, '\0');
  330. ASSERT(p != NULL);
  331. pEndOfLine = p;
  332. --p;
  333. while (isspace(*p))
  334. {
  335. if (p == pLine)
  336. break;
  337. --p;
  338. }
  339. if (!isspace(*p))
  340. ++p;
  341. if (p == pEndOfLine)
  342. continue;
  343. bResult = DeleteCharacterBlock(pFile, i, p - pLine, i, pEndOfLine - pLine - 1);
  344. if (!bResult)
  345. goto _exit_point;
  346. *pnBlanksRemoved += pEndOfLine - p;
  347. }
  348. _exit_point:
  349. UNDO_BLOCK_END(nUndoEntry, bResult);
  350. return bResult;
  351. }
  352. /*
  353. This software is distributed under the conditions of the BSD style license.
  354. Copyright (c)
  355. 1995-2002
  356. Petar Marinov
  357. All rights reserved.
  358. Redistribution and use in source and binary forms, with or without
  359. modification, are permitted provided that the following conditions
  360. are met:
  361. 1. Redistributions of source code must retain the above copyright
  362. notice, this list of conditions and the following disclaimer.
  363. 2. Redistributions in binary form must reproduce the above copyright
  364. notice, this list of conditions and the following disclaimer in the
  365. documentation and/or other materials provided with the distribution.
  366. 3. The name of the author may not be used to endorse or promote products
  367. derived from this software without specific prior written permission.
  368. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  369. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  370. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  371. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  372. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  373. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  374. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  375. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  376. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  377. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  378. */