home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / smapp100.zip / sm10.zip / smgflow.c < prev    next >
C/C++ Source or Header  |  2000-05-14  |  31KB  |  852 lines

  1. /* ------------------------------------------------------------------------
  2.  *
  3.  *        File: smgflow.c
  4.  *     Project: Source Mapper.
  5.  *     Created: Mai 12, 1993.
  6.  * Description: Sourcecode to include calling sequence info to mapfile.
  7.  *
  8.  * Copyright (C) 2000 Leif-Erik Larsen.
  9.  * This file is part of the Source Mapper source package.
  10.  * Source Mapper is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published
  12.  * by the Free Software Foundation, in version 2 as it comes in the
  13.  * "COPYING" file of the XWorkplace main distribution.
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * ------------------------------------------------------------------------ */
  20.  
  21.  
  22.  
  23.  
  24. #include "smg.h"
  25.  
  26.  
  27.  
  28.  
  29. typedef struct
  30. {
  31.    char name [MAXFUNCN + 1];
  32.    long lnr;
  33. }
  34.    levelTYPE;
  35.  
  36.  
  37.  
  38.  
  39. /* Below is a structure of data used by the reqursive function
  40.    'FlowCSubLevels ()'. This items is better stored in such a global
  41.    structure, instead of passing them as arguments on each reqursive call
  42.    to the function. This to prevent unneccessary use of the stack.
  43.    This structure must be initialized before the function 'FlowCSubLevels ()'
  44.    is called first time. */
  45.  
  46. static struct
  47. {
  48.    FILE     *mapf;                     /* Map file to include the list       */
  49.    FILE     *tmpf;                     /* Stripped temporary objectfile      */
  50.    char      topl [MAXFUNCN + 1];      /* Name of function in current level  */
  51.    long      lnr;                      /* Number of next line in the list    */
  52.    int       indent;                   /* Current number of indents in list  */
  53. }
  54.    req;
  55.  
  56.  
  57.  
  58.  
  59. int FlowCIncludeToMap ( FILE *mapf )
  60. /*
  61.         Function: Include calling sequence info to mapfile.
  62.    Programmed by: LEL
  63.             Date: Mai, 12. 1993. 13:35.
  64.        Interface: mapf = Map file to include info of calling sequences.
  65.          Returns: E/O.
  66. */
  67. {
  68.    int        ok;
  69.    FILE      *objf;                    /* Main objectfile                    */
  70.    fposTYPE   fpos;                    /* Positions of blocks of data in objf*/
  71.    prjfeTYPE  fdata;                   /* Data about source in project       */
  72.  
  73.    if (!prjstat.prjon)                 /* If no active project               */
  74.    {
  75.       return (ERROR);
  76.    }
  77.  
  78.    /* =======================================================================*/
  79.    /* List of calling sequences:                                             */
  80.    /*                                                                        */
  81.    /*                                                                        */
  82.  
  83.    WrtStdLinComStart (mapf, stdwidth, linechr2);
  84.    FPrintF (mapf, "%s:\n\n\n", _StrMSGFLOWCLSTSTR);
  85.  
  86.    if (errno != 0)                     /* Any error when writing header?     */
  87.       return (ERROR);
  88.  
  89.    if (prjstat.filc == 1)              /* If only one source in project      */
  90.    {
  91.       /* Get name of normal objectfile */
  92.       if (!GetFDataFromPrj (1, &fdata))
  93.          RETURN_ERR;
  94.  
  95.       /* Use normal objfile if only 1 source */
  96.       if ((objf = FOpen (fdata.objn, "r+b")) == NULL)
  97.          RETERR (16, tmpn.manobj);     /* Failed on open file! */
  98.    }
  99.    else
  100.    {
  101.       /* Use main objectfile if several files */
  102.       if ((objf = FOpen (tmpn.manobj, "r+b")) == NULL)
  103.          RETERR (16, tmpn.manobj);     /* Failed on open file! */
  104.    }
  105.  
  106.    if (!GetFPosTYPE (objf, &fpos))     /* Read position of blocks of data    */
  107.    {
  108.       FClose (objf);                   /* Yes, so close objectfile before ret*/
  109.       RETURN_ERR;
  110.    }
  111.  
  112.    ok = FlowCIncludeToMap_ (mapf, objf, &fpos); /* Make calling sequence */
  113.  
  114.    FClose (objf);                      /* Close main objectfile              */
  115.  
  116.    return (ok);                        /* OK generate of function index      */
  117. } /* FlowCIncludeToMap (); */
  118.  
  119.  
  120.  
  121.  
  122. int IsFuncCalled ( FILE *objf, const char *funcn, fposTYPE *fpos, int *answ )
  123. /*
  124.         Function:
  125.    Programmed by: LEL
  126.             Date: Mai, 12. 1993. 15:03.
  127.        Interface: objf  = Opened, main objectfile.
  128.                   funcn = Name of function to test if called.
  129.                   fpos  = Positions to blocks of data in objectfile.
  130.                   answ  = Returns answer: 1 if function is called, else 0.
  131.          Returns: E/O.
  132. */
  133. {
  134.    char caller [MAXFUNCN + 1];         /* Buffer for storing name of function*/
  135.    long lnr;                           /* Buffer for storing dummy line numbr*/
  136.    long currpos;                       /* Current position of objectfile     */
  137.  
  138.    *answ = 0;                          /* Default is that func is not called */
  139.  
  140.    /* Seek to start of function call list */
  141.    FSeek (objf, fpos->funcal, SEEK_SET);
  142.  
  143.    currpos = fpos->funcal;             /* Init current position controller */
  144.    while (currpos < fpos->idlst)       /* Next datablock is list of id's */
  145.    {
  146.       if (!FGetS0 (caller, MAXFUNCN, objf)) /* Read name of called function */
  147.          return (ERROR);
  148.  
  149.  
  150.       if (strcmp (funcn, caller) == 0) /* Compare called func. with func.name*/
  151.       {
  152.          *answ = 1;                    /* Yes, so function is called         */
  153.          return (OK);                  /* OK test                            */
  154.       }
  155.  
  156.       do                               /* Do a dummy seek past line numbers  */
  157.       {
  158.          if (!FGetL (objf, &lnr))      /* Read next line number */
  159.             return (ERROR);
  160.       }
  161.       while (lnr != 0);                /* A 0L terminates block of callers   */
  162.  
  163.       currpos = FTell (objf);          /* Update current position controller */
  164.    }
  165.  
  166.    return (OK);                        /* OK test. Function not called       */
  167. } /* IsFuncCalled (); */
  168.  
  169.  
  170.  
  171.  
  172. int FlowCIncludeToMap_ ( FILE *mapf, FILE *objf, fposTYPE *fpos )
  173. /*
  174.     Function: Include calling sequence info of a single sourcefile
  175.               to mapfile.
  176.         Date: Mai, 12. 1993. 13:40. LEL.
  177.    Interface: mapf = Map file to include info of calling sequences.
  178.               objf = Newly opened main objectfile.
  179.               fpos = File positions to blocks of data in main objectfile.
  180.      Returns: E/O.
  181. */
  182. {
  183.    int        answ;                    /* Store answers                      */
  184.    int        ctopl;                   /* Number of top level functions      */
  185.    long       c1;                      /* Counter 1                          */
  186.    long       lnr = 1;                 /* Count line number in list          */
  187.    FILE      *diff;                    /* File of top-level functions        */
  188.    FILE      *tmpf;                    /* Temporary file of stripped list    */
  189.    funcTYPE   func;                    /* Info on current function           */
  190.    levelTYPE  level;
  191.  
  192.    /* Seeks for top-level functions */
  193.    Display (D_HEIGH, "%s", _StrMSGSEEKTPLEVELF);
  194.  
  195.    /* Init list of non-caled/top-level */
  196.    if (!DiffBConstruct (tmpn.sortfi, MAXFUNCN + 1))
  197.    {
  198.       DiffBDestruct ();                /* Terminate list of included funccals */
  199.       RETURN_ERR;
  200.    }
  201.  
  202.    c1 = 0;                             /* Reset controller of display-info */
  203.  
  204.    /* Get info about next function */
  205.    while (FuncRBuffIndxGet (c1++, &func))
  206.    {
  207.       if (c1 % 4 == 0)                 /* Update userinfo on each 4 */
  208.          Display (D_LOW, "%s: %ld%%", _StrMSGSEEKTPLEVELF, (c1 * 100) / FuncRBuffGetFNr ());
  209.  
  210.       /* Test if function is called */
  211.       if (!IsFuncCalled (objf, func.name, fpos, &answ))
  212.       {
  213.          DiffBDestruct ();             /* Terminate table of non-called funcs */
  214.          RETURN_ERR;
  215.       }
  216.  
  217.       if (answ == 0)                   /* Is function called? */
  218.       {
  219.          if (!DiffBAddId (func.name))  /* No, so add name of function to list*/
  220.          {
  221.             DiffBDestruct ();          /* Terminate table of non-called funcs*/
  222.             RETURN_ERR;
  223.          }
  224.       }
  225.    }
  226.  
  227.    /* Seeks for top-level functions: 100% */
  228.    Display (D_LOW, "%s: 100%%", _StrMSGSEEKTPLEVELF);
  229.  
  230.    ctopl = diffb.cid;                  /* Copy number of top-level functions */
  231.    if (ctopl < 1)                      /* Any non-called function?           */
  232.    {
  233.       /* Warning: No top level function */
  234.       Display (D_WARNING, "%s: %s ()", _StrMSGNOTOPLEVELFUNC, o_flow.deftoplev);
  235.  
  236.       /* Test if default name of top-level function is in function buffer:   */
  237.       if (FuncRBuffIsFunc (o_flow.deftoplev))
  238.       {
  239.          if (!DiffBAddId (o_flow.deftoplev))
  240.          {
  241.             DiffBDestruct ();          /* Terminate table of non-called funcs*/
  242.             RETURN_ERR;
  243.          }
  244.       }
  245.  
  246.       /* If default name of top-level function is not in function-buffer,
  247.          then we know that this function is not defined in the project.
  248.          Therefore, we have no top-level function to start flow-chart from,
  249.          so do nothing more but return a dummy OK: */
  250.  
  251.       else                             /* Default top-level isn't in buffer  */
  252.       {
  253.          DiffBDestruct ();             /* Terminate table of non-called funcs*/
  254.          return (OK);
  255.       }
  256.    }
  257.  
  258.    DiffBDestruct ();                   /* Terminate table of non-called funcs*/
  259.  
  260.    /*------------------------------------------------------------------------*/
  261.  
  262.    /* Open file of top-level functions */
  263.    if ((diff = FOpen (tmpn.sortfi, "r+b")) == NULL)
  264.       RETERR (11, tmpn.sortfi);        /* Failed on open temporary file! */
  265.  
  266.    if (!sortfile (diff, MAXFUNCN + 1)) /* Sort list of top-level functions   */
  267.    {
  268.       FClose (diff);
  269.       RETERR (12, GetFNames (diff));   /* Failed on sort contents of file! */
  270.    }
  271.  
  272.    /* Init list of allready included functions */
  273.    if (!DiffBConstruct (tmpn.funcal, sizeof (levelTYPE)))
  274.    {
  275.       DiffBDestruct ();                /* Terminate list of included funccals*/
  276.       FClose (diff);
  277.       RETURN_ERR;
  278.    }
  279.  
  280.    /* Open temporary strip file for writing */
  281.    if ((tmpf = FOpen (tmpn.idlist, "w+b")) == NULL)
  282.    {
  283.       DiffBDestruct ();                /* Terminate list of included funccals*/
  284.       FClose (diff);
  285.       RETERR (11, tmpn.idlist);        /* Failed on open temporary file! */
  286.    }
  287.  
  288.    /* Strip objectfile into 'tmpf' */
  289.    if (!FlowCStripTmpf (objf, tmpf, fpos))
  290.    {
  291.       FClose (tmpf);
  292.       DiffBDestruct ();                /* Terminate list of included funccals*/
  293.       FClose (diff);
  294.       RETURN_ERR;
  295.    }
  296.  
  297.    /* Loop trough all top-level functions */
  298.    for (c1 = 0; c1 < ctopl; c1++)
  299.    {
  300.       /* Read name of next top-level function */
  301.       if (FRead (&func.name, MAXFUNCN + 1, 1, diff) != 1)
  302.       {
  303.          FClose (tmpf);
  304.          DiffBDestruct ();             /* Terminate list of included funccals*/
  305.          FClose (diff);
  306.          return (ERROR);
  307.       }
  308.  
  309.       strcpy (level.name, func.name);  /* Name of top level function         */
  310.       level.lnr = lnr;                 /* Line number of calling sequence    */
  311.  
  312.       /* Add it to list of allready included */
  313.       if (!DiffBAddId ((char *) &level))
  314.       {
  315.          FClose (tmpf);                /* Yes, so close files before return  */
  316.          DiffBDestruct ();             /* Terminate list of included funccals*/
  317.          FClose (diff);
  318.          RETURN_ERR;
  319.       }
  320.  
  321.       /* Include cal.-seq. for this top-level */
  322.       if (!FlowCIncludeToMap__ (mapf, tmpf, func.name, &lnr))
  323.       {
  324.          FClose (tmpf);                /* Close files before return  */
  325.          DiffBDestruct ();             /* Terminate list of included funccals*/
  326.          FClose (diff);
  327.          RETURN_ERR;
  328.       }
  329.  
  330.       if (c1 < ctopl - 1)
  331.       {
  332.          FPrintF     (mapf, "\n\n");   /* New-lines between each top-level   */
  333.          WritFLineLn (mapf, stdwidth, linechr1);
  334.       }
  335.    }
  336.  
  337.    FClose (tmpf);                      /* Close temporary strip-file         */
  338.    DiffBDestruct ();                   /* Terminate list of included funccals*/
  339.    FClose (diff);                      /* Close list of top-level functions  */
  340.  
  341.    /*------------------------------------------------------------------------*/
  342.  
  343.    if (o_flow.index != O_YES)          /* Shall we include index-register?   */
  344.    {
  345.       if (o_various.gencom == O_YES)   /* No, so terminate eventually comment*/
  346.          WrtComEndLn (mapf);
  347.  
  348.       goto OK_RET;                     /* And jump past include of index     */
  349.    }
  350.  
  351.    /* Re-open list of included functions */
  352.    if ((diff = FOpen (tmpn.funcal, "r+b")) == NULL)
  353.       RETERR (11, tmpn.funcal);        /* Failed on open temporary file! */
  354.  
  355.    Display (D_HEIGH, "%s", _StrMSGSORTFLOWIDXREG); /* Display info to user */
  356.  
  357.    if (!sortfile (diff, sizeof (levelTYPE))) /* Sort included functions */
  358.    {
  359.       FClose (diff);
  360.       RETERR (12, GetFNames (diff));   /* Failed on sort contents of file! */
  361.    }
  362.  
  363.    if (!FlowCInclIndx (mapf, diff))    /* Include index-register to map      */
  364.    {
  365.       FClose (diff);
  366.       RETURN_ERR;
  367.    }
  368.  
  369.    FClose (diff);
  370.  
  371. OK_RET:
  372.  
  373.    FPrintF (mapf, "\n\n\n");
  374.    if (o_various.np_sect == O_YES)     /* Page break between map sections? */
  375.       FPrintF (mapf, "%c", NPCHR);     /* Yes, so include new-page character */
  376.  
  377.    if (errno != 0)                     /* Any error on last I/O operations?  */
  378.       return (ERROR);
  379.  
  380.    return (OK);
  381. } /* FlowCIncludeToMap_ (); */
  382.  
  383.  
  384.  
  385.  
  386. int FlowCStripTmpf ( FILE *objf, FILE *tmpf, fposTYPE *fpos )
  387. /*
  388.     Function: Strip info of function calls in file 'objf' into
  389.               temporary file 'tmpf'. Whit this, we mean:
  390.               Strip away all superfluous line number references so that
  391.               no calles have more than one line number reference to
  392.               each mother function.
  393.         Date: Mai, 13. 1993. 10:40. By LEL.
  394.    Interface: objf = Objectfile to strip.
  395.               tmpf = Store stripped data in this file.
  396.               fpos = File-positions to blocks of data in 'objf'.
  397.      Returns: E/O.
  398. */
  399. {
  400.    long     line;                      /* Store line number of function-call */
  401.    long     currpos;                   /* Current position in objectfile     */
  402.    char     fname [MAXFUNCN + 1];      /* Name of current function-call      */
  403.    char     last  [MAXFUNCN + 1];      /* Name of last stripped function-call*/
  404.    funcTYPE func;                      /* Info of function                   */
  405.  
  406.    Display (D_HEIGH, "%s", _StrMSGFLOWGENSTRIP);
  407.  
  408.    FSeek (objf,fpos->funcal,SEEK_SET); /* Seek to start of function-calls    */
  409.    currpos = fpos->funcal;             /* Init controller of file position   */
  410.    while (currpos < fpos->idlst)       /* Loop to strip objf into 'tmpf'     */
  411.    {
  412.       FGetS0 (fname, MAXFUNCN, objf);  /* Read name of next function-call    */
  413.       FPrintF (tmpf, "%s%c",           /* Update strip file with this caller */
  414.                      fname, '\0');     /* Terminate the name with a '\0'-char*/
  415.  
  416.       if (errno != 0)                  /* Any error on last I/O?             */
  417.       {
  418.          FClose (tmpf);                /* Yes, so close temp. file before ret*/
  419.          return (ERROR);
  420.       }
  421.  
  422.       last[0] = '\0';                  /* Reset buffer of last stripped call */
  423.  
  424.       while (1)                        /* Loop to include and strip line-nrs */
  425.       {
  426.          FGetL (objf, &line);          /* Read next line number              */
  427.  
  428.          if (errno != 0)               /* Any error on last I/O?             */
  429.          {
  430.             FClose (tmpf);             /* Yes, so close temp. file before ret*/
  431.             return (ERROR);
  432.          }
  433.  
  434.          if (line <= 0)                /* A 0L indicate the end of the linnrs*/
  435.             break;                     /* So, break the loop of line-reading */
  436.  
  437.          /* To whitch function does line belong? */
  438.          if (FuncRBuffLNrGet (line, &func))
  439.          {
  440.             /* Is owner another than current func? */
  441.             if (strcmp (func.name, fname) != 0)
  442.             {
  443.                /* Yes, so test if current functioncall is already called by
  444.                   function */
  445.                if (strcmp (last, func.name) == 0)
  446.                   continue;            /* Don't include more than once       */
  447.  
  448.                strcpy (last,func.name);/* Remember name of last owner func.  */
  449.  
  450.                if (!FPutL (tmpf, line))
  451.                {
  452.                   FClose (tmpf);
  453.                   return (ERROR);
  454.                }
  455.             }
  456.          }
  457.       }
  458.       currpos = FTell (objf);          /* Update controller of file position */
  459.       FPutL (tmpf, 0L);                /* Include a 0L to mark end of lines  */
  460.    }
  461.  
  462.    return (OK);                        /* OK stripping                       */
  463. } /* FlowCStripTmpf (); */
  464.  
  465.  
  466.  
  467.  
  468. int FlowCIncludeToMap__ ( FILE *mapf, FILE *tmpf, const char *topl, long *lnr )
  469. /*
  470.     Function: Include calling sequence to mapfile.
  471.         Date: Mai, 12. 1993. 16:45. By LEL.
  472.    Interface: mapf = Map file to include info of calling sequences.
  473.               tmpf = Stripped data of function calls.
  474.               fpos = File positions to blocks of data in main objectfile.
  475.               topl = Name of current top-level function.
  476.               lnr  = Number of next line in the list.
  477.      Returns: E/O.
  478. */
  479. {
  480.    int  ret;                           /* Value to return                    */
  481.    int  indent = 0;                    /* Current level of indent            */
  482.    static char str [MAXFUNCN + 5];
  483.  
  484.    sprintf (str, "%s ()", topl);       /* Include top level function to list */
  485.    if (!FlowCDrawBox (mapf, *lnr, 0, str))
  486.       RETURN_ERR;
  487.  
  488.    req.mapf   =  mapf;                 /* Init items used by reqursive func  */
  489.    req.tmpf   =  tmpf;
  490.    req.lnr    = (*lnr)++;
  491.    req.indent =  indent;
  492.    strcpy (req.topl, topl);
  493.  
  494.    ret = FlowCSubLevels ();            /* Pass into reqursive function       */
  495.  
  496.    *lnr = req.lnr + 1;                 /* Update counter of number of lines  */
  497.  
  498.    return (ret);
  499. } /* FlowCIncludeToMap__ (); */
  500.  
  501.  
  502.  
  503.  
  504. int FlowCSubLevels ( void )
  505. /*
  506.     Function: Include sub-levels of call-sequence from specified
  507.               name of function ('topl').
  508.         Date: Mai, 12. 1993. 18:40. By LEL.
  509.    Interface: See declaration of global structure 'req' at top of file.
  510.      Returns: E/O.
  511. */
  512. {
  513.    static int  washere = FALSE;
  514.    char        fname [MAXFUNCN + 1];
  515.    static char swap  [MAXFUNCN + 1];
  516.    static char str   [MAXFUNCN + 35];
  517.    long             currpos;
  518.    long             line;
  519.    static uint16    answ;
  520.    static funcTYPE  func;
  521.    static levelTYPE level;
  522.  
  523.    req.indent += 1;                    /* A new indent of call-sequence      */
  524.  
  525.    FSeek (req.tmpf, 0L, SEEK_SET);     /* Seek to start of file              */
  526.    currpos = 0L;                       /* Init controller of current filepos */
  527.  
  528.    /* Info to user. Do this only once, to prevent the message from
  529.       flashing due to reqursive calls to this function. */
  530.    if (!washere)
  531.    {
  532.       washere = TRUE;
  533.       Display (D_HEIGH, "%s", _StrMSGINCLFLOWC);
  534.    }
  535.  
  536.    /* Loop to include sub-calls */
  537.    while (FGetS0 (fname, MAXFUNCN, req.tmpf)) /* Name of next caller */
  538.    {
  539.       while (1)                        /* Loop to find sub-calls             */
  540.       {
  541.          FGetL (req.tmpf, &line);      /* Read next line number ref.         */
  542.          if (line <= 0)                /* A 0L indicate the end of the linnrs*/
  543.             break;                     /* So, break the loop of line-reading */
  544.  
  545.          currpos = FTell (req.tmpf);   /* Update controller of current f.pos.*/
  546.  
  547.          /* We allready know that the line is owned by a function, because
  548.             we did such a test in function 'FlowCStripTmpf ()' when we
  549.             searched and stripped line number references:                      */
  550.          FuncRBuffLNrGet (line,&func); /* Read name of owner function        */
  551.  
  552.          /* If owner equal actual level-func (which is in req.topl) */
  553.          if (strcmp (func.name, req.topl) == 0)
  554.          {
  555.             req.lnr += 1;              /* Count linenumber in list */
  556.  
  557.             DiffBIfId (fname, &answ);  /* See if sub-sequence allready incl. */
  558.             if (answ == 0)             /* If not allready included */
  559.             {
  560.                /* Info to user */
  561.                Display (D_LOW, "%s (%c-%ld)", _StrMSGINCLFLOWC, LOCLINCHR, req.lnr);
  562.  
  563.                /* Test if called function is in buffer of functions. If
  564.                   so, then we know that the called function is a function
  565.                   which is defined in some of the source files of the
  566.                   project. Then we allso must include a sub-sequence of the
  567.                   called function. If called function is not in buffer of
  568.                   functions, then we know that the called function is a
  569.                   function which is an external: */
  570.  
  571.                if (!FuncRBuffIsFunc (fname))
  572.                {
  573.                   /* Function is not in buffer, so mark it as an external */
  574.                   if (o_flow.iIncExternals)
  575.                   {
  576.                      sprintf (str, "%s () %s", fname, _StrMSGEXTERNAL);
  577.                      if (!FlowCDrawBox (req.mapf, req.lnr, req.indent, str))
  578.                         RETURN_ERR;
  579.                   }
  580.                   else
  581.                   {
  582.                      req.lnr -= 1;     /* Don't count this skipped function */
  583.                   }
  584.                   continue;            /* Don't include sub-sequence(s) */
  585.                }
  586.  
  587.                /* Called function is in buffer */
  588.                sprintf (str, "%s ()", fname);
  589.                if (!FlowCDrawBox (req.mapf, req.lnr, req.indent, str))
  590.                   RETURN_ERR;
  591.  
  592.                /* So, prepare for add it to list of allready included
  593.                   sub-sequences    */
  594.                strcpy (level.name, fname);
  595.                level.lnr = req.lnr;    /* The sub-sequence start at cur.line */
  596.  
  597.                /* Add it to list of allready included functions */
  598.                if (!DiffBAddId ((char *) &level))
  599.                   RETURN_ERR;
  600.  
  601.                strcpy (swap, req.topl);/* Swap 'req.topl' and 'fname'        */
  602.                strcpy (req.topl,fname);
  603.                strcpy (fname, swap);
  604.  
  605.                if (!FlowCSubLevels ()) /* Do reqursive sub-sequences         */
  606.                   RETURN_ERR;
  607.  
  608.                strcpy (req.topl,fname);/* Restore current mother function    */
  609.  
  610.                /* Restore current file position */
  611.                FSeek (req.tmpf, currpos, SEEK_SET);
  612.             }
  613.  
  614.             else                       /* Sub-sequence allready included     */
  615.             {
  616.                /* So, get info of where it was incl. */
  617.                if (!DiffBGetId (answ, (char *) &level))
  618.                   RETURN_ERR;
  619.  
  620.                /* Reference of where sub-sequence is included */
  621.                sprintf (str, "%s () ... [%c-%ld]", fname, LOCLINCHR, level.lnr);
  622.  
  623.                if (!FlowCDrawBox (req.mapf, req.lnr, req.indent, str))
  624.                   RETURN_ERR;
  625.             }
  626.          }
  627.       }
  628.  
  629.       currpos = FTell (req.tmpf);      /* Update controller of current f.pos.*/
  630.    }
  631.  
  632.    req.indent -= 1;                    /* Finished this level of sub-sequence*/
  633.  
  634.    return (OK);                        /* OK include of sub-sequence         */
  635. } /* FlowCSubLevels (); */
  636.  
  637.  
  638.  
  639.  
  640. int FlowCDrawIndts ( FILE *mapf, int indent, char vertchr )
  641. /*
  642.     Function: Draw specified number of indents.
  643.         Date: Mai, 13. 1993. 10:55. By LEL.
  644.    Interface: mapf   = Map file of where to draw the indents.
  645.               indent = Levele of indents.
  646.               vertchr= Character to use when draw vertical lines.
  647.      Returns: E/O.
  648. */
  649. {
  650.    while (indent-- > 0)
  651.    {
  652.       FPutC (mapf, vertchr);
  653.       WritFLine (mapf, o_flow.indent - 1, ' ');
  654.       if (errno != 0)
  655.          return (ERROR);
  656.    }
  657.  
  658.    return (OK);
  659. } /* FlowCDrawIndts (); */
  660.  
  661.  
  662.  
  663.  
  664. int FlowCDrawBox ( FILE *mapf, long lnr, int indent, const char *txt )
  665. /*
  666.     Function: Draw a single item of call sequence to mapfile.
  667.               The item is drawed in respect to the options
  668.               'o_flow.box' amd 'o_flow.graph', whitch is used to
  669.               determind if
  670.         Date: Mai, 13. 1993. 10:50. By LEL.
  671.    Interface: mapf   = Map file to draw the item of call sequence.
  672.               lnr    = Current line number/number of item.
  673.               indent = Current level of indents.
  674.               txt    = Item text (name of function, etc.)
  675.      Returns: E/O.
  676.      Comment: The item is drawed in respect to the options 'o_flow.box'
  677.               and 'o_flow.graph', whitch is used to determind if
  678.               items shall be drawed as boxes or as brief listing, and
  679.               if we shall use graphical characters or not in the list.
  680. */
  681. {
  682.    int ret;
  683.    static char graphchr[] = "│└─>║║╔═╗╚╝";
  684.    static char textchr [] = "|+--||+-+++";
  685.  
  686.    if (o_flow.graph == O_YES)
  687.       ret = FlowCDrawBox_ (mapf, lnr, indent, txt, graphchr);
  688.    else
  689.       ret = FlowCDrawBox_ (mapf, lnr, indent, txt, textchr);
  690.  
  691.    return (ret);
  692. } /* FlowCDrawBox (); */
  693.  
  694.  
  695.  
  696.  
  697. int FlowCDrawBox_ ( FILE *mapf, long lnr, int indent,
  698.                     const char *txt, const char chrs[] )
  699. /*
  700.     Function: Kernel function of the function 'FlowCDrawBox ()'.
  701.               Do the real draw of box of flowchart or (if call-sequence
  702.               has the format of brief list) include single item to
  703.               call-sequence.
  704.         Date: Mai, 14. 1993. 00:28. By LEL.
  705.    Interface: mapf   = Map file to draw the item of call sequence.
  706.               lnr    = Current line number/number of item.
  707.               indent = Current level of indents.
  708.               txt    = Item text (name of function, etc.
  709.               chrs   = Characters to use when eventually draw a box.
  710.                        Se function 'FlowCDrawBox ()' where the two
  711.                        different sets of characters are defined.
  712.  
  713.                        Graphical version of the string is:
  714.                        chrs[0] = '│'
  715.                        chrs[1] = '└'
  716.                        chrs[2] = '─'
  717.                        chrs[3] = '>'
  718.                        chrs[4] = '║'
  719.                        chrs[5] = '║'
  720.                        chrs[6] = '╔'
  721.                        chrs[7] = '═'
  722.                        chrs[8] = '╗'
  723.                        chrs[9] = '╚'
  724.                        chrs[10]= '╝'
  725.      Returns: E/O.
  726. */
  727. {
  728.    if (o_flow.format == O_LIST)        /* If user do not wish chart as boxes */
  729.    {
  730.       FPrintF        (mapf, "%c-%ld\t", LOCLINCHR, lnr);
  731.       FlowCDrawIndts (mapf, indent, chrs[0]);
  732.       FPrintF        (mapf, "%s\n", txt);
  733.  
  734.       if (errno != 0)
  735.          return (ERROR);
  736.  
  737.       return (OK);
  738.    }
  739.  
  740.    if (indent > 0)                     /* If level is not top level-function */
  741.    {
  742.       FPrintF        (mapf, "\t");
  743.       FlowCDrawIndts (mapf, indent, chrs[0]);
  744.       FPrintF        (mapf, "\n");
  745.    }
  746.  
  747.    FPrintF        (mapf, "%c-%ld\t", LOCLINCHR, lnr);
  748.    FlowCDrawIndts (mapf, indent, chrs[0]);
  749.  
  750.    FPutC          (mapf, chrs[6]);
  751.    WritFLine      (mapf, strlen (txt) + 4, chrs[7]);
  752.    FPrintF        (mapf, "%c\n", chrs[8]);
  753.  
  754.    FPrintF        (mapf, "\t");
  755.  
  756.    if (indent > 0)
  757.    {
  758.       FlowCDrawIndts (mapf, indent - 1, chrs[0]);
  759.       FPutC          (mapf, chrs[1]);
  760.       WritFLine      (mapf, o_flow.indent - 2, chrs[2]);
  761.       FPutC          (mapf, chrs[3]);
  762.    }
  763.  
  764.    if (indent > 0)
  765.       FPutC       (mapf, chrs[4]);
  766.    else
  767.       FPutC       (mapf, chrs[5]);
  768.    WritFLine      (mapf, 2, ' ');
  769.    FPrintF        (mapf, "%s", txt);
  770.    WritFLine      (mapf, 2, ' ');
  771.    FPrintF        (mapf, "%c\n", chrs[5]);
  772.  
  773.    FPrintF        (mapf, "\t");
  774.    if (indent > 0)
  775.    {
  776.       FlowCDrawIndts (mapf, indent - 1, chrs[0]);
  777.       WritFLine      (mapf, o_flow.indent, ' ');
  778.    }
  779.  
  780.    FPutC          (mapf, chrs[9]);
  781.    WritFLine      (mapf, strlen (txt) + 4, chrs[7]);
  782.    FPrintF        (mapf, "%c\n", chrs[10]);
  783.  
  784.    if (errno != 0)
  785.       return (ERROR);
  786.  
  787.    return (OK);
  788. } /* FlowCDrawBox_ (); */
  789.  
  790.  
  791.  
  792.  
  793. int FlowCInclIndx ( FILE *mapf, FILE *funcs )
  794. /*
  795.         Function: Include index-register of call-sequences to mapfile.
  796.    Programmed by: LEL
  797.             Date: Mai, 14. 1993. 03:50.
  798.        Interface: mapf  = File of where to include the index-register.
  799.                   funcs = File with sorted functions which is included in
  800.                           the call-sequence list.
  801.          Returns: E/O.
  802. */
  803. {
  804.    long      c1 = 0;                   /* Count index number                 */
  805.    levelTYPE func;                     /* Store current function index       */
  806.  
  807.    /* Be sure position is at start of file */
  808.    if (!FSeek (funcs, 0L, SEEK_SET))
  809.       return (ERROR);
  810.  
  811.    /* ---------------------------------------------------------------------- */
  812.    /* Index register of calling sequences:                                   */
  813.    /*                                                                        */
  814.  
  815.    FPrintF     (mapf, "\n\n\n");
  816.    WritFLineLn (mapf, stdwidth, linechr1);
  817.    FPrintF     (mapf, "%s:\n\n", _StrMSGIDXREGFLOW);
  818.  
  819.    if (errno != 0)                     /* Any error when writing header?     */
  820.    {
  821.       return (ERROR);
  822.    }
  823.  
  824.    /* Display info to user */
  825.    Display (D_HEIGH, "%s", _StrMSGINCLFLOWIDXREG);
  826.  
  827.    /* Loop and read all items in file */
  828.    while (FRead (&func, sizeof (levelTYPE), 1, funcs) == 1)
  829.    {
  830.       Display (D_LOW, "%s: (%s ())", _StrMSGINCLFLOWIDXREG, func.name);
  831.  
  832.       /* F-nn   NameOfFunction ()    L-nnn */
  833.       FPrintF (mapf, "\n%c-%ld\t%s ()\t%c-%ld",
  834.                      FUNCTIONCHR, ++c1, func.name, LOCLINCHR, func.lnr);
  835.  
  836.       if (errno != 0)                  /* Any error when writing index?      */
  837.          return (ERROR);
  838.    }
  839.  
  840.    if (o_various.gencom == O_YES)      /* Shall we generate comment-blocks?  */
  841.       WrtComEndLn (mapf);              /* Yes, so terminate current comment  */
  842.    else
  843.       FPrintF (mapf, "\n");            /* No, so only include a line feed    */
  844.  
  845.    if (errno != 0)                     /* Any error on last I/O operations?  */
  846.       return (ERROR);
  847.  
  848.    return (OK);                        /* OK include of index register       */
  849. } /* FlowCInclIndx (); */
  850.  
  851.  
  852.