home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / fte0108.zip / FTE_SRC.ZIP / fte / src / e_tags.cpp < prev    next >
C/C++ Source or Header  |  2001-05-27  |  14KB  |  590 lines

  1. /*    e_tags.cpp *
  2.  *    Copyright (c) 1994-1996, Marko Macek
  3.  *
  4.  *    You may distribute under the terms of either the GNU General Public
  5.  *    License or the Artistic License, as specified in the README file.
  6.  *
  7.  */
  8.  
  9. #include "fte.h"
  10.  
  11. #ifdef CONFIG_TAGS
  12. struct TagData {
  13.     int Tag;        // tag name pos
  14.     int FileName;
  15.     int TagBase;    // name of tag file
  16.     int Line;
  17.     int StrFind;    // string to find
  18. };
  19.  
  20. struct TagStack {
  21.     char *FileName;
  22.     int Line, Col;
  23.     TagStack *Next;
  24.     int TagPos;
  25.     char *CurrentTag;
  26. };
  27.  
  28. static char *TagMem = 0;
  29. static int TagLen = 0;
  30. static int ATagMem  = 0;
  31.  
  32. static int CTags = 0;            // number of tags
  33. static int ATags = 0;
  34. static TagData *TagD = 0;
  35. static int *TagI = 0;
  36. static int TagFileCount = 0;
  37. static int *TagFiles = 0;
  38.  
  39. static int TagFilesLoaded = 0;   // tag files are loaded at first lookup
  40. static char *CurrentTag = 0;
  41. static int TagPosition = -1;
  42. static TagStack *TStack;
  43.  
  44. static int AllocMem(char *Mem, int Len) { /*FOLD00*/
  45.     int N = 1024;
  46.     char *NM;
  47.     int TagPos = TagLen;
  48.  
  49.     while (N < TagLen + Len) N <<= 1;
  50.     if (ATagMem < N || TagMem == 0) {
  51.         NM = (char *)realloc((void *)TagMem, N);
  52.         if (NM == 0)
  53.             return -1;
  54.         TagMem = NM;
  55.         ATagMem = N;
  56.     }
  57.     memcpy(TagMem + TagLen, Mem, Len);
  58.     TagLen += Len;
  59.     return TagPos;
  60. }
  61.  
  62. static int AddTag(int Tag, int FileName, int TagBase, int Line, int StrFind) { /*FOLD00*/
  63.     int N;
  64.  
  65.     N = 1024;
  66.     while (N < CTags + 1) N <<= 1;
  67.     if (ATags < N || TagD == 0) {
  68.         TagData *ND;
  69.  
  70.         ND = (TagData *)realloc((void *)TagD, N * sizeof(TagData));
  71.         if (ND == 0)
  72.             return -1;
  73.         TagD = ND;
  74.         ATags = N;
  75.     }
  76.     TagD[CTags].Tag = Tag;
  77.     TagD[CTags].Line = Line;
  78.     TagD[CTags].FileName = FileName;
  79.     TagD[CTags].TagBase = TagBase;
  80.     TagD[CTags].StrFind = StrFind;
  81.     CTags++;
  82.     return 0;
  83. }
  84.  
  85. #if defined(__IBMCPP__)
  86. int _LNK_CONV cmptags(const void *p1, const void *p2) {
  87. #else
  88. int cmptags(const void *p1, const void *p2) {
  89. #endif
  90.     return strcmp(TagMem + TagD[*(int *)p1].Tag,
  91.                   TagMem + TagD[*(int *)p2].Tag);
  92. }
  93.  
  94. int SortTags() { /*FOLD00*/
  95.     int *NI;
  96.     int i;
  97.  
  98.     if (CTags == 0)
  99.         return 0;
  100.  
  101.     NI = (int *)realloc((void *)TagI, CTags * sizeof(int));
  102.     if (NI == 0)
  103.         return -1;
  104.     TagI = NI;
  105.     for (i = 0; i < CTags; i++)
  106.         TagI[i] = i;
  107.  
  108.     qsort(TagI, CTags, sizeof(TagI[0]), cmptags);
  109.  
  110.     return 0;
  111. }
  112.  
  113. int TagsLoad(int id) { /*FOLD00*/
  114.     //char line[2048];
  115.     char *tags;
  116.     int fd;
  117.     struct stat sb;
  118.     long size;
  119.  
  120.     free(TagI);
  121.     TagI = 0;
  122.  
  123.     if ((fd = open(TagMem + TagFiles[id], O_BINARY | O_RDONLY)) == -1)
  124.         return -1;
  125.  
  126.     if (fstat(fd, &sb) == -1)
  127.         return -1;
  128.  
  129.     if ((tags = (char *)malloc(sb.st_size)) == 0) {
  130.         close(fd);
  131.         return -1;
  132.     }
  133.  
  134.     size = read(fd, tags, sb.st_size);
  135.     close(fd);
  136.     if (size != sb.st_size)
  137.         return -1;
  138.  
  139.     if (TagMem == 0) { // preallocate (useful when big file)
  140.         char *NM;
  141.  
  142.         NM = (char *)realloc((void *)TagMem, TagLen + sb.st_size);
  143.         if (NM != 0) {
  144.             TagMem = NM;
  145.             ATagMem = TagLen + sb.st_size;
  146.         }
  147.     }
  148.  
  149.     char *p = tags;
  150.     char *e = tags + sb.st_size;
  151.  
  152.     char *LTag, *LFile, *LLine;
  153.     int TagL, FileL/*, LineL*/;
  154.     int MTag, MFile;
  155.  
  156.     while (p < e) {
  157.         LTag = p;
  158.         while (p < e && *p != '\t') p++;
  159.         if (p < e && *p == '\t') *p++ = 0;
  160.         else break;
  161.         TagL = p - LTag;
  162.         LFile = p;
  163.         while (p < e && *p != '\t') p++;
  164.         if (p < e && *p == '\t') *p++ = 0;
  165.         else break;
  166.         FileL = p - LFile;
  167.         LLine = p;
  168.         while (p < e && *p != '\r' && *p != '\n') p++;
  169.         if (p < e && *p == '\r') *p++ = 0;           // optional
  170.         if (p < e && *p == '\n') *p++ = 0;
  171.         else break;
  172.         //LineL = p - LLine;
  173.  
  174.         MTag = AllocMem(LTag, TagL + FileL);
  175.  
  176.         if (MTag == -1)
  177.             break;
  178.  
  179.         MFile = MTag + TagL;
  180.  
  181.         if (LLine[0] == '/') {
  182.             char *AStr = LLine;
  183.             char *p = AStr + 1;
  184.             char *d = AStr;
  185.             int MStr;
  186.  
  187.             while (*p) {
  188.                 if (*p == '\\') {
  189.                     p++;
  190.                     if (*p)
  191.                         *d++ = *p++;
  192.                 } else if (*p == '^' || *p == '$') p++;
  193.                 else if (*p == '/')
  194.                     break;
  195.                 else
  196.                     *d++ = *p++;
  197.             }
  198.             *d = 0;
  199.             if (stricmp(d - 10, "/*FOLD00*/") == 0)
  200.                 d[-11] = 0; /* remove our internal folds */
  201.  
  202.             MStr = AllocMem(AStr, strlen(AStr) + 1);
  203.             if (MStr == -1)
  204.                 break;
  205.  
  206.             if (AddTag(MTag, MFile, TagFiles[id], -1, MStr) == -1)
  207.                 break;
  208.         } else {
  209.             if (AddTag(MTag, MFile, TagFiles[id], atoi(LLine), -1) == -1)
  210.                 break;
  211.         }
  212.     }
  213.     free(tags);
  214.     return 0;
  215. }
  216.  
  217. int TagsAdd(char *FileName) { /*FOLD00*/
  218.     int *NewT;
  219.     int NewF;
  220.  
  221.     NewF = AllocMem(FileName, strlen(FileName) + 1);
  222.     if (NewF == -1)
  223.         return 0;
  224.  
  225.     NewT = (int *)realloc((void *)TagFiles, (TagFileCount + 1) * sizeof(int));
  226.     if (NewT == 0)
  227.         return 0;
  228.     TagFiles = NewT;
  229.     TagFiles[TagFileCount++] = NewF;
  230.     return 1;
  231. }
  232.  
  233. int TagsSave(FILE *fp) { /*FOLD00*/
  234.     for (int i = 0; i < TagFileCount; i++)
  235.         fprintf(fp, "T|%s\n", TagMem + TagFiles[i]);
  236.     return 1;
  237. }
  238.  
  239. static void ClearTagStack() { /*FOLD00*/
  240.     TagStack *T;
  241.  
  242.     if (CurrentTag) {
  243.         free(CurrentTag);
  244.         CurrentTag = 0;
  245.     }
  246.     TagPosition = -1;
  247.     while (TStack) {
  248.         T = TStack;
  249.         TStack = TStack->Next;
  250.  
  251.         free(T->CurrentTag);
  252.         free(T->FileName);
  253.         free(T);
  254.     }
  255. }
  256.  
  257. int TagLoad(char *FileName) { /*FOLD00*/
  258.     if (TagsAdd(FileName) == 0)
  259.         return 0;
  260.     ClearTagStack();
  261.     if (TagFilesLoaded) {
  262.         if (TagsLoad(TagFileCount - 1) == -1) {
  263.             return 0;
  264.         }
  265.         if (SortTags() == -1) {
  266.             TagClear();
  267.             return 0;
  268.         }
  269.     }
  270.     return 1;
  271. }
  272.  
  273. static int LoadTagFiles() { /*FOLD00*/
  274.     int i;
  275.  
  276.     assert(TagFilesLoaded == 0);
  277.     for (i = 0; i < TagFileCount; i++)
  278.         if (TagsLoad(i) == -1) {
  279.             TagClear();
  280.             return 0;
  281.         }
  282.     if (SortTags() == -1) {
  283.         TagClear();
  284.         return 0;
  285.     }
  286.     TagFilesLoaded = 1;
  287.     return 1;
  288. }
  289.  
  290. void TagClear() { /*FOLD00*/
  291.     free(TagD);
  292.     free(TagI);
  293.     TagD = 0;
  294.     TagI = 0;
  295.     CTags = 0;
  296.     ATags = 0;
  297.  
  298.     free(TagFiles);
  299.     TagFiles = 0;
  300.     TagFileCount = 0;
  301.     TagFilesLoaded = 0;
  302.  
  303.     free(TagMem);
  304.     TagMem = 0;
  305.     TagLen = 0;
  306.     ATagMem = 0;
  307.  
  308.     ClearTagStack();
  309. }
  310.  
  311. static int GotoFilePos(EView *View, char *FileName, int Line, int Col) { /*FOLD00*/
  312.     if (FileLoad(0, FileName, 0, View) == 0)
  313.         return 0;
  314.     if (((EBuffer *)ActiveModel)->Loaded == 0)
  315.         ((EBuffer *)ActiveModel)->Load();
  316.     ((EBuffer *)ActiveModel)->CenterNearPosR(Col, Line);
  317.     return 1;
  318. }
  319.  
  320. static int GotoTag(int M, EView *View) { /*FOLD00*/
  321.     char path[MAXPATH];
  322.     char Dir[MAXPATH];
  323.     TagData *TT = &TagD[TagI[M]];
  324.  
  325.     JustDirectory(TagMem + TT->TagBase, Dir);
  326.  
  327.     if (IsFullPath(TagMem + TT->FileName)) {
  328.         strcpy(path, TagMem + TT->FileName);
  329.     } else {
  330.         strcpy(path, Dir);
  331.         Slash(path, 1);
  332.         strcat(path, TagMem + TT->FileName);
  333.     }
  334.     if (TT->Line != -1) {
  335.         if (GotoFilePos(View, path, TT->Line - 1, 0) == 0)
  336.             return 0;
  337.     } else {
  338.         if (GotoFilePos(View, path, 0, 0) == 0)
  339.             return 0;
  340.         if (((EBuffer *)ActiveModel)->FindStr(TagMem + TT->StrFind, strlen(TagMem + TT->StrFind), 0) == 0)
  341.             return 0;
  342.     }
  343.     ((EBuffer *)ActiveModel)->FindStr(TagMem + TT->Tag, strlen(TagMem + TT->Tag), 0);
  344.     return 1;
  345. }
  346.  
  347. static int PushPos(EBuffer *B) { /*FOLD00*/
  348.     TagStack *T;
  349.  
  350.     T = (TagStack *)malloc(sizeof(TagStack));
  351.     if (T == 0)
  352.         return 0;
  353.     T->FileName = strdup(B->FileName);
  354.     if (T->FileName == 0) {
  355.         free(T);
  356.         return 0;
  357.     }
  358.     T->Line = B->VToR(B->CP.Row);
  359.     T->Col = B->CP.Col;
  360.     T->Next = TStack;
  361.     T->CurrentTag = CurrentTag;
  362.     CurrentTag = 0;
  363.     T->TagPos = TagPosition;
  364.     TagPosition = -1;
  365.     TStack = T;
  366.     return 1;
  367. }
  368.  
  369. int TagGoto(EView *View, char *Tag) {
  370.     assert(Tag != 0);
  371.  
  372.     if (TagFilesLoaded == 0)
  373.         if (LoadTagFiles() == 0)
  374.             return 0;
  375.  
  376.     int L = 0, R = CTags, M, cmp;
  377.  
  378.     if (CTags == 0)
  379.         return 0;
  380.  
  381.     while (L < R) {
  382.         M = (L + R) / 2;
  383.         cmp = strcmp(Tag, TagMem + TagD[TagI[M]].Tag);
  384.         if (cmp == 0) {
  385.             while (M > 0 && strcmp(Tag, TagMem + TagD[TagI[M - 1]].Tag) == 0)
  386.                 M--;
  387.  
  388.             if (GotoTag(M, View) == 0)
  389.                 return 0;
  390.  
  391.             CurrentTag = strdup(Tag);
  392.             TagPosition = M;
  393.             return 1;
  394.         } else if (cmp < 0) {
  395.             R = M;
  396.         } else {
  397.             L = M + 1;
  398.         }
  399.     }
  400.     return 0; // tag not found
  401. }
  402.  
  403. int TagFind(EBuffer *B, EView *View, char *Tag) { /*FOLD00*/
  404.     assert(View != 0 && Tag != 0 && B != 0);
  405.  
  406.     if (TagFilesLoaded == 0)
  407.         if (LoadTagFiles() == 0)
  408.             return 0;
  409.  
  410.     int L = 0, R = CTags, M, cmp;
  411.  
  412.     if (CurrentTag) {
  413.         if (strcmp(CurrentTag, Tag) == 0) {
  414.             if (PushPos(B) == 0)
  415.                 return 0;
  416.  
  417.             CurrentTag = strdup(Tag);
  418.             if (CurrentTag == 0)
  419.                 return 0;
  420.             TagPosition = TStack->TagPos;
  421.  
  422.             return TagNext(View);
  423.         }
  424.     }
  425.  
  426.     if (CTags == 0)
  427.         return -1;
  428.  
  429.     while (L < R) {
  430.         M = (L + R) / 2;
  431.         cmp = strcmp(Tag, TagMem + TagD[TagI[M]].Tag);
  432.         if (cmp == 0) {
  433.             while (M > 0 && strcmp(Tag, TagMem + TagD[TagI[M - 1]].Tag) == 0)
  434.                 M--;
  435.  
  436.             if (PushPos(B) == 0)
  437.                 return 0;
  438.  
  439.             if (GotoTag(M, View) == 0)
  440.                 return 0;
  441.  
  442.             CurrentTag = strdup(Tag);
  443.             TagPosition = M;
  444.  
  445.             return 1;
  446.         } else if (cmp < 0) {
  447.             R = M;
  448.         } else {
  449.             L = M + 1;
  450.         }
  451.     }
  452.     return 0; // tag not found
  453. }
  454.  
  455. int TagDefined(char *Tag) {
  456.     int L = 0, R = CTags, M, cmp;
  457.  
  458.     if (TagFilesLoaded == 0) // !!! always?
  459.         if (LoadTagFiles() == 0)
  460.             return 0;
  461.  
  462.     if (CTags == 0)
  463.         return 0;
  464.     
  465.     while (L < R) {
  466.         M = (L + R) / 2;
  467.         cmp = strcmp(Tag, TagMem + TagD[TagI[M]].Tag);
  468.         if (cmp == 0)
  469.             return 1;
  470.         else if (cmp < 0)
  471.             R = M;
  472.         else
  473.             L = M + 1;
  474.     }
  475.     return 0; // tag not found
  476. }
  477.  
  478. int TagComplete(char **Words, int *WordsPos, int WordsMax, char *Tag) {
  479.     if ((Tag == NULL) || (Words == NULL) || (*WordsPos >= WordsMax))
  480.         return 0;
  481.  
  482.     if (TagFilesLoaded == 0)
  483.         if (LoadTagFiles() == 0)
  484.             return 0;
  485.  
  486.     if (CTags == 0)
  487.         return 0;
  488.  
  489.     int L = 0, R = CTags, len = strlen(Tag);
  490.  
  491.     while (L < R) {
  492.         int c, M;
  493.  
  494.         M = (L + R) / 2;
  495.         c = strncmp(Tag, TagMem + TagD[TagI[M]].Tag, len);
  496.         if (c == 0) {
  497.             while (M > 0 &&
  498.                    strncmp(Tag, TagMem + TagD[TagI[M - 1]].Tag, len) == 0)
  499.                 M--;            // find begining
  500.             int N = M, w = 0;
  501.             while(strncmp(Tag, TagMem + TagD[TagI[N]].Tag, len) == 0) {
  502.                 // the first word is not tested for previous match
  503.                 if (!w || strcmp(TagMem + TagD[TagI[N]].Tag,
  504.                                  TagMem + TagD[TagI[N-1]].Tag)) {
  505.                     int l = strlen(TagMem + TagD[TagI[N]].Tag) - len;
  506.                     if (l > 0) {
  507.                         char *s = new char[l + 1];
  508.                         if (s != NULL) {
  509.                             strcpy(s, TagMem + TagD[TagI[N]].Tag + len);
  510.                             Words[(*WordsPos)++] = s;
  511.                             w++; // also mark the first usage
  512.                             if (*WordsPos >= WordsMax)
  513.                                 break;
  514.                         } else
  515.                             break;  // how about using exceptions
  516.                     }
  517.                 }
  518.                 N++;
  519.             }
  520.             return w;
  521.         } else if (c < 0) {
  522.             R = M;
  523.         } else {
  524.             L = M + 1;
  525.         }
  526.     }
  527.     return 0; // tag not found
  528. }
  529.  
  530. int TagNext(EView *View) { /*FOLD00*/
  531.     assert(View != 0);
  532.  
  533.     if (CurrentTag == 0 || TagPosition == -1) {
  534.         return 0;
  535.     }
  536.  
  537.     if (TagPosition < CTags - 1 && strcmp(CurrentTag, TagMem + TagD[TagI[TagPosition + 1]].Tag) == 0) {
  538.         TagPosition++;
  539.         if (GotoTag(TagPosition, View) == 0)
  540.             return 0;
  541.         return 1;
  542.     }
  543.     View->Msg(S_INFO, "No next match for tag.");
  544.     return 0;
  545. }
  546.  
  547. int TagPrev(EView *View) { /*FOLD00*/
  548.     assert(View != 0);
  549.  
  550.     if (CurrentTag == 0 || TagPosition == -1) {
  551.         View->Msg(S_INFO, "No current tag.");
  552.         return 0;
  553.     }
  554.  
  555.     if (TagPosition > 0 && strcmp(CurrentTag, TagMem + TagD[TagI[TagPosition - 1]].Tag) == 0) {
  556.         TagPosition--;
  557.         if (GotoTag(TagPosition, View) == 0)
  558.             return 0;
  559.         return 1;
  560.     }
  561.     View->Msg(S_INFO, "No previous match for tag.");
  562.     return 0;
  563. }
  564.  
  565. int TagPop(EView *View) { /*FOLD00*/
  566.     TagStack *T = TStack;
  567.  
  568.     assert(View != 0);
  569.  
  570.     if (T) {
  571.         TStack = T->Next;
  572.  
  573.         if (CurrentTag)
  574.             free(CurrentTag);
  575.         CurrentTag = T->CurrentTag;
  576.         TagPosition = T->TagPos;
  577.  
  578.         if (GotoFilePos(View, T->FileName, T->Line, T->Col) == 0) {
  579.             free(T);
  580.             return 0;
  581.         }
  582.         free(T);
  583.         return 1;
  584.     }
  585.     View->Msg(S_INFO, "Tag stack empty.");
  586.     return 0;
  587. }
  588.  
  589. #endif
  590.