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

  1. /* ------------------------------------------------------------------------
  2.  *
  3.  *        File: smglinf.c
  4.  *     Project: Source Mapper.
  5.  *     Created: January 10, 1993.
  6.  * Description: Sourcecode to include sourcetext and lineinfo 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. #define COLWIDTH 9                     /* Width of info-column to the left   */
  30.  
  31.  
  32.  
  33.  
  34. int LInfoIncToMap ( FILE *mapf )
  35. /*
  36.         Function: Include source and lineinfo to map file.
  37.    Programmed by: LEL
  38.             Date: Januar, 10. 1993.
  39.        Interface: mapf = Map file to include source list.
  40.          Returns: E/O.
  41. */
  42. {
  43.    if (!prjstat.prjon)                 /* Any sources in current project?    */
  44.    {
  45.       return (ERROR);
  46.    }
  47.  
  48.    if (prjstat.filc == 1)              /* If one single source in project    */
  49.       return (LInfo1 (mapf));          /* Adjusted to single list of source  */
  50.    else                                /* If more than one source in project */
  51.       return (LInfo2 (mapf));          /* Adjust to list of several sources  */
  52. } /* LInfoIncToMap (); */
  53.  
  54.  
  55.  
  56.  
  57. int LInfoSourceHead ( FILE *mapf, int fnr )
  58. /*
  59.     Function: Include header of specified source file in project, to map.
  60.         Date: Mai, 7. 1993. 01:55. By LEL.
  61.    Interface: mapf = Map file to include header.
  62.               fnr  = File number index of projectsource (1..).
  63.      Returns: E/O.
  64. */
  65. {
  66.    if (prjstat.filc > 1)               /* If more than one source in project */
  67.    {
  68.       if (!wrt_totinfo1 (mapf, fnr))   /* Header as info of active source    */
  69.       {
  70.          RETURN_ERR;
  71.       }
  72.       return (OK);                     /* OK include of source header        */
  73.    }
  74.  
  75.    errno = 0;                          /* Reset any error                    */
  76.  
  77.    WrtStdLinComStart (mapf, stdwidth, linechr2);
  78.    FPrintF (mapf, "%s:", _StrMSGSOURCECODEINF);
  79.  
  80.    if (o_various.gencom)               /* Generate comment-blocks?           */
  81.    {
  82.       WrtComEnd (mapf);                /* Yes, so terminate block of comment */
  83.    }
  84.  
  85.    FPrintF (mapf, "\n\n");             /* Write new-lines after header       */
  86.  
  87.    if (errno != 0)                     /* Any error when writing mapfile     */
  88.    {
  89.       return (ERROR);
  90.    }
  91.  
  92.    return (OK);                        /* OK include of header               */
  93. } /* LInfoSourceHead (); */
  94.  
  95.  
  96.  
  97.  
  98. int LInfo1 ( FILE *mapf )
  99. /*
  100.         Function: Include source adjusted to a single sourcefile.
  101.    Programmed by: LEL
  102.             Date: Mai, 7. 1993. 01:50.
  103.        Interface: mapf = Map file to include source list.
  104.          Returns: E/O.
  105. */
  106. {
  107.    int       ret;
  108.    long      glnr = 1;                 /* Number of next global line         */
  109.    FILE     *objf;                     /* Objectfile                         */
  110.    FILE     *srcf;                     /* Sourcefile                         */
  111.    fposTYPE  fpos;                     /* Positions to blocks of data in objf*/
  112.    prjfeTYPE fdata;
  113.  
  114.    if (!GetFDataFromPrj (1, &fdata))   /* Get info about sourcefile          */
  115.    {
  116.       RETURN_ERR;
  117.    }
  118.  
  119.    /* Open objectfile */
  120.    if ((objf = FOpen (fdata.objn, "r+b")) == NULL)
  121.    {
  122.       RETERR (16, fdata.objn);         /* Failed on open file! */
  123.    }
  124.  
  125.    if (!GetFPosTYPE (objf, &fpos))     /* Get position to blocks of data     */
  126.    {
  127.       FClose (objf);
  128.       RETURN_ERR;
  129.    }
  130.  
  131.    FSeek (objf, fpos.lininf, SEEK_SET);/* Point to start of lineinfo         */
  132.  
  133.    if (!LInfoSourceHead (mapf, 1))     /* Include header of sourcefile       */
  134.    {
  135.       FClose (objf);
  136.       RETURN_ERR;
  137.    }
  138.  
  139.    /* Open the sourcefile */
  140.    if ((srcf = FOpen (fdata.name, "rt")) == NULL)
  141.    {
  142.       FClose (objf);
  143.       RETERR (23, fdata.name);         /* Failed on open source file! */
  144.    }
  145.  
  146.    /* Include sourceline with info */
  147.    ret = LInfoInclSource (mapf, objf, srcf, &glnr, fdata.finf.ltot, &fpos);
  148.  
  149.    FClose (srcf);                      /* Close current sourcefile           */
  150.    FClose (objf);                      /* Close main objectfile              */
  151.  
  152.    return (ret);
  153. } /* LInfo1 (); */
  154.  
  155.  
  156.  
  157.  
  158. int LInfo2 ( FILE *mapf )
  159. /*
  160.         Function: Include source adjusted to several sourcefiles.
  161.    Programmed by: LEL
  162.             Date: Mai, 7. 1993. 01:50.
  163.        Interface: mapf = Map file to include source list.
  164.          Returns: E/O.
  165. */
  166. {
  167.    int       fc = 0;                   /* Count current file in project      */
  168.    long      glnr = 1;                 /* Number of next global line         */
  169.    FILE     *objf;                     /* Main objectfile                    */
  170.    FILE     *srcf;                     /* Current sourcefile                 */
  171.    fposTYPE  fpos;                     /* Positions to blocks of data in objf*/
  172.    prjfeTYPE fdata;
  173.  
  174.    /* Open main objectfile */
  175.    if ((objf = FOpen (tmpn.manobj, "r+b")) == NULL)
  176.    {
  177.       /* Failed on open temporary file! */
  178.       RETERR (11, tmpn.manobj);
  179.    }
  180.  
  181.    if (!GetFPosTYPE (objf, &fpos))     /* Get position to blocks of data     */
  182.    {
  183.       FClose (objf);
  184.       RETURN_ERR;
  185.    }
  186.  
  187.    FSeek (objf, fpos.lininf, SEEK_SET);/* Point to start of lineinfo         */
  188.  
  189.    while (fc++ < prjstat.filc)         /* All sources in project             */
  190.    {
  191.       if (!LInfoSourceHead (mapf, fc)) /* Include header of current source   */
  192.       {
  193.          FClose (objf);
  194.          RETURN_ERR;
  195.       }
  196.  
  197.       /* Get info about current sourcefile */
  198.       if (!GetFDataFromPrj (fc, &fdata))
  199.       {
  200.          FClose (objf);
  201.          RETURN_ERR;
  202.       }
  203.  
  204.       /* Open current sourcefile */
  205.       if ((srcf = FOpen (fdata.name, "rt")) == NULL)
  206.       {
  207.          FClose (objf);
  208.          RETERR (23, fdata.name);      /* Failed on open sourcefile! */
  209.       }
  210.  
  211.       /* Include sourceline with info */
  212.       if (!LInfoInclSource (mapf, objf, srcf, &glnr, fdata.finf.ltot, &fpos))
  213.       {
  214.          FClose (objf);
  215.          FClose (srcf);
  216.          RETURN_ERR;
  217.       }
  218.  
  219.       FClose (srcf);                   /* Close current sourcefile           */
  220.    }
  221.  
  222.    FClose (objf);                      /* Close main objectfile              */
  223.  
  224.    return (OK);                        /* OK include of lineinfo             */
  225. } /* LInfo2 (); */
  226.  
  227.  
  228.  
  229.  
  230. int LInfoInclSource ( FILE *mapf, FILE *objf,
  231.                       FILE *srcf, long *glnr, long lines, fposTYPE *fpos )
  232. /*
  233.     Function: Include specified source to mapfile.
  234.         Date: Mai, 14. 1993. 15:20. By LEL.
  235.    Interface: mapf = Map file to include source list.
  236.               objf = Main objectfile.
  237.               srcf = Current sourcefile.
  238.               glnr = Number of next global line.
  239.               lines= Number of lines in current sourcefile.
  240.               fpos = Positions to blocks of data in main objectfile.
  241.      Returns: E/O.
  242.      Comment: The file 'objf' must point to start of block of lineinfo of
  243.               specified source.
  244.               The file 'srcf' must point to the start of file.
  245. */
  246. {
  247.    int      oldblock = 0;              /* Last number of block-indent        */
  248.    long     llnr;                      /* Local line number                  */
  249.    char     line[MAXINLIN+1];          /* Store current sourceline           */
  250.    char     fname[MAXFILE+MAXEXT+1];   /* Name of current sourcefile         */
  251.    scanTYPE scan;                      /* Scaninfo of current sourceline     */
  252.    funcTYPE func;                      /* Info of next function              */
  253.  
  254.    /* Get name of current sourcefile */
  255.    strcpy (fname, GetFName (GetFNames (srcf)));
  256.  
  257.    /* Includes sourceinfo: XXXXX.X */
  258.    Display (D_HEIGH, "%s: %s", _StrMSGINCLINEINFO, fname);
  259.  
  260.    /* Find next func. after current line */
  261.    if (!LInfoFindNextFunc (*glnr, &func))
  262.    {
  263.       RETURN_ERR;
  264.    }
  265.  
  266.    for (llnr = 1;                      /* Loop trough all lines in sourcefile*/
  267.         llnr <= lines;
  268.         llnr++, (*glnr)++)             /* Allso count global line number     */
  269.    {
  270.       if (o_lineinfo.r_func)           /* If include of function info        */
  271.       {
  272.          if (func.blin != 0 &&         /* If any next function               */
  273.              *glnr==func.blin_block)   /* If cur. line is start of next func.*/
  274.          {
  275.             /* Include all function info to map */
  276.             if (!LInfoInclFuncInfo (mapf, objf, &func, fpos))
  277.             {
  278.                RETURN_ERR;
  279.             }
  280.  
  281.             /* Find next func. after current line */
  282.             if (!LInfoFindNextFunc (*glnr, &func))
  283.             {
  284.                RETURN_ERR;
  285.             }
  286.          }
  287.       }
  288.  
  289.       if (llnr % 10 == 0)              /* Update userinfo on each 10. line   */
  290.       {
  291.          /* Includes sourceinfo: XXXXX.X (nnn) */
  292.          Display (D_LOW, "%s: %s (%ld)", _StrMSGINCLINEINFO, fname, llnr);
  293.       }
  294.  
  295.       /* Get scaninfo of current sourceline */
  296.       FRead (&scan, sizeof (scan), 1, objf);
  297.  
  298.       FGetS (line, MAXINLIN, srcf);    /* Get current sourceline             */
  299.  
  300.       if (errno != 0)                  /* Any error on last I/O's?           */
  301.       {
  302.          return (ERROR);
  303.       }
  304.  
  305.       if (scan.block > oldblock)       /* Inc. block only when block started */
  306.       {
  307.          oldblock = scan.block;        /* Remember last block-indent         */
  308.          scan.block--;                 /* Adjust number of block-indent      */
  309.       }
  310.       else
  311.       {
  312.          oldblock = scan.block;        /* Remember last block-indent         */
  313.       }
  314.  
  315.       /* Call kernel function */
  316.       if (!LInfoInclSource_ (mapf, line, &scan, llnr, *glnr))
  317.       {
  318.          RETURN_ERR;
  319.       }
  320.    }
  321.  
  322.    ClrLin ();
  323.    FPrintF (mapf, "\n\n\n");           /* Linefeeds between each sourcefile  */
  324.  
  325.    return (OK);                        /* OK include of sourceline/info      */
  326. } /* LInfoInclSource () */
  327.  
  328.  
  329.  
  330.  
  331. int LInfoInclSource_ ( FILE *mapf, const char *line, scanTYPE *scan,
  332.                        long llnr, long glnr )
  333. /*
  334.         Function: Kernel function of 'LInfo2InclSource'. Include specified
  335.                   line of source to mapfile.
  336.    Programmed by: LEL
  337.             Date: Mai, 19. 1993. 02:20.
  338.        Interface: mapf = Map file to include source line.
  339.                   line = Current source line.
  340.                   scan = Scan info of current line.
  341.                   llnr = Number of current local line.
  342.                   glnr = Number of current global line.
  343.          Returns: E/O.
  344. */
  345. {
  346.    int   c1;                           /* Counter 1                          */
  347.    int   len;                          /* Length of new-page string          */
  348.    char *ptr = (char *) line;          /* Pointer to current line            */
  349.  
  350.    /* Test if current line is a newpage-line only if both user has asked us
  351.       to include newpages wherever such strings appear and if user has
  352.       entered such a line.
  353.    */
  354.  
  355.    if (o_various.np_str &&             /* If newpage when string for newpage */
  356.        o_various.newpag[0])            /* And any string for newpage         */
  357.    {
  358.       len = strlen (o_various.newpag); /* Length of string for new-page      */
  359.  
  360.       for (c1 = 0; c1 < len; c1++)     /* Compare characters with newpage-str*/
  361.       {
  362.          if (*ptr++ != o_various.newpag[c1]) /* If strings are not equal */
  363.             break;                     /* Then this is not a new-page line   */
  364.       }
  365.  
  366.       if (c1 >= len)                   /* If the two strings was equal       */
  367.          FPutC (mapf, NPCHR);          /* Then insert new-page character     */
  368.    }
  369.  
  370.    if (scan->dirl &&                   /* Is current line a directive?       */
  371.        o_various.gencom)               /* And generate comment-blocks        */
  372.    {
  373.       /* Since user has asked SMG to generate comment-blocks around info
  374.          that SM includes, we can not write any info in front of any
  375.          directive line. This is because any directiveline must start
  376.          at line without any comment or source in front. Since we generates
  377.          comments, we must suppose user wont to compile the generated map.
  378.          Therefore, we now must include an empty block of info, instead of
  379.          the normal block of info,
  380.       */
  381.  
  382.       if (!LInfoEmpty (mapf))          /* Include an empty block of info     */
  383.       {
  384.          RETURN_ERR;
  385.       }
  386.  
  387.       /* Include current sourceline */
  388.       if (!PrintStrTab (mapf, line, o_various.twidth))
  389.       {
  390.          RETURN_ERR;
  391.       }
  392.  
  393.       return (OK);                     /* OK include of current sourceline   */
  394.    }
  395.  
  396.    if (o_various.gencom)               /* Shall we generate comment-blocks?  */
  397.    {
  398.       if (!scan->com1)                 /* Yes, but allready inside comment?  */
  399.       {
  400.          if (!WrtComStart (mapf))
  401.             return (ERROR);
  402.       }
  403.       else
  404.       {
  405.          /* Since allready in com, write spaces */
  406.          if (!WritFLine (mapf, 3, ' '))
  407.             return (ERROR);
  408.       }
  409.    }
  410.  
  411.    /* L=Local line#, G=Global line# */
  412.    FPrintF (mapf, "%c-%ld", prjstat.filc == 1 ? LOCLINCHR : GLOBLINCHR, glnr);
  413.  
  414.    /* Tabulate into next column */
  415.    WritFLine (mapf, COLWIDTH - StrLenSL (glnr) - 2, ' ');
  416.  
  417.    if (prjstat.filc > 1 &&             /* If several sourcefiles             */
  418.        o_lineinfo.r_llin)              /* and we shall include local linenr  */
  419.    {
  420.       /* then include number of local line  */
  421.       FPrintF (mapf, "%c-%ld", LOCLINCHR, llnr);
  422.  
  423.       /* Tabulate into next column */
  424.       WritFLine (mapf, COLWIDTH - StrLenSL (llnr) - 2, ' ');
  425.    }
  426.  
  427.    if (scan->ocom)                     /* If whole line is comment */
  428.    {
  429.       if (o_lineinfo.r_coml)           /* and user has asked us to mark coml */
  430.       {
  431.          /* Mark line as comment-line */
  432.          FPrintF   (mapf, "%s", _StrMSGONLYCOMENT);
  433.  
  434.          /* Tabulate into next column */
  435.          WritFLine (mapf, COLWIDTH - strlen (_StrMSGONLYCOMENT), ' ');
  436.       }
  437.       else
  438.       if (o_lineinfo.r_bloc)
  439.       {
  440.          WritFLine (mapf, COLWIDTH, ' '); /* Tabulate into next column */
  441.       }
  442.    }
  443.  
  444.    else
  445.    if (scan->emp)                      /* If line is empty */
  446.    {
  447.       if (o_lineinfo.r_bloc ||         /* Report blocklevel */
  448.           o_lineinfo.r_coml)           /* Report comment lines */
  449.       {
  450.          WritFLine (mapf, COLWIDTH, ' '); /* Tabulate into next column */
  451.       }
  452.    }
  453.  
  454.    else
  455.    if (scan->block > 0 &&              /* If we are inside any level of block*/
  456.        o_lineinfo.r_bloc)              /* and user has asked us to report it */
  457.    {
  458.       FPrintF (mapf, "%c", BLOCKCHR);  /* Write character for level of block */
  459.  
  460.       c1 = scan->block - 1;            /* Number of leading characters       */
  461.       if (c1 > COLWIDTH - 3)           /* can not be greater than 6          */
  462.       {
  463.          c1 = COLWIDTH - 3;            /* Hold width inside 0-6              */
  464.       }
  465.       WritFLine (mapf, c1, '-');       /* Write leading characters           */
  466.  
  467.       /* Write level of block */
  468.       FPrintF   (mapf, "%d", scan->block);
  469.  
  470.       /* Tabulate into next column */
  471.       WritFLine (mapf, COLWIDTH - c1 - 2, ' ');
  472.    }
  473.  
  474.    else
  475.    if (o_lineinfo.r_bloc ||            /* If we use the mark-column          */
  476.        o_lineinfo.r_coml)
  477.    {
  478.       WritFLine (mapf, COLWIDTH, ' '); /* Tabulate into next column          */
  479.    }
  480.  
  481.    FPutC (mapf, '|');                  /* Include vertical separating line   */
  482.  
  483.    if (o_various.gencom)               /* Shall we generate comment-blocks?  */
  484.    {
  485.       if (!scan->com1)                 /* Yes, but allready inside comment?  */
  486.       {
  487.          if (!WrtComEnd (mapf))        /* No, so start block of comment      */
  488.          {
  489.             return (ERROR);
  490.          }
  491.       }
  492.       else
  493.       {
  494.          /* Since allready in com, write spaces */
  495.          if (!WritFLine (mapf, 3, ' '))
  496.          {
  497.             return (ERROR);
  498.          }
  499.       }
  500.    }
  501.  
  502.    if (errno != 0)                     /* Any error on last I/O's?           */
  503.    {
  504.       return (ERROR);
  505.    }
  506.  
  507.    /* Include current sourceline */
  508.    if (!PrintStrTab (mapf, line, o_various.twidth))
  509.    {
  510.       return (ERROR);
  511.    }
  512.  
  513.    return (OK);                        /* OK include of source/info          */
  514. } /* LInfoInclSource_ (); */
  515.  
  516.  
  517.  
  518.  
  519. int LInfoEmpty ( FILE *mapf )
  520. /*
  521.     Function: Write an empty info-column to the left of where source
  522.               line is to be written.
  523.         Date: Mai, 19. 1993. 12:30. By LEL.
  524.    Interface: mapf = Map file to include the empty info.
  525.      Returns: E/O.
  526. */
  527. {
  528.    if (o_various.gencom)               /* If user has asked us to gen. comm. */
  529.    {
  530.       WritFLine (mapf, 3, ' ');        /* Replace comment with spaces        */
  531.    }
  532.  
  533.    WritFLine (mapf, COLWIDTH, ' ');    /* Replace global line number         */
  534.  
  535.    if (prjstat.filc > 1 &&             /* If several sourcefiles             */
  536.        o_lineinfo.r_llin)              /* If we shall report number of locals*/
  537.    {
  538.       WritFLine (mapf, COLWIDTH, ' '); /* Replace local line number          */
  539.    }
  540.  
  541.    if (o_lineinfo.r_bloc ||            /* If we use the mark-column          */
  542.        o_lineinfo.r_coml)
  543.    {
  544.       WritFLine (mapf, COLWIDTH, ' '); /* Replace mark-column                */
  545.    }
  546.  
  547.    FPutC (mapf, ' ');                  /* Replace '|'-character              */
  548.  
  549.    if (o_various.gencom)               /* If user has asked us to gen. comm. */
  550.    {
  551.       WritFLine (mapf, 3, ' ');        /* Replace comment with spaces        */
  552.    }
  553.  
  554.    if (errno != 0)                     /* Any error on last I/O's?           */
  555.    {
  556.       return (ERROR);
  557.    }
  558.  
  559.    return (OK);                        /* OK include of empty info           */
  560. } /* LInfoEmpty (); */
  561.  
  562.  
  563.  
  564.  
  565. int LInfoFindNextFunc ( long curlnr, funcTYPE *func )
  566. /*
  567.     Function: Find next function after specified global line number.
  568.         Date: Mai, 19. 1993. 15:20. By LEL.
  569.    Interface: curlnr = Start seek from this global line number.
  570.               func   = Store eventually found function here.
  571.      Returns: E/O.
  572.      Comment: If there are no more functions after that global line
  573.               number, then return 'func->blin' with the value 0.
  574.               Else this item consist of the true starting line number
  575.               of the found next function.
  576. */
  577. {
  578.    long c1;                            /* Counter 1                          */
  579.    long fnr;                           /* Number of functions                */
  580.    long nearest = 0;                   /* Nearest found line number of next  */
  581.  
  582.    fnr = FuncRBuffGetFNr ();           /* Get number of functions in buffer  */
  583.  
  584.    for (c1 = 0; c1 < fnr; c1++)        /* Seek trough all functions          */
  585.    {
  586.       FuncRBuffIndxGet (c1, func);     /* Get function which has this index  */
  587.  
  588.       if (curlnr <= func->blin)        /* If this function is after linenr   */
  589.       {
  590.          /* If no nearest is found yet or this function is nearer */
  591.          if (nearest == 0 || func->blin < nearest)
  592.          {
  593.             nearest = func->blin;      /* then this is the nearest found now */
  594.          }
  595.       }
  596.    }
  597.  
  598.    if (nearest == 0)                   /* If no nearest function was found   */
  599.    {
  600.       func->blin = 0;                  /* No more functions after that line  */
  601.    }
  602.  
  603.    /* Get function who own found nearest  */
  604.    if (FuncRBuffLNrGet (nearest, func) == 0) /* If no function own that line */
  605.    {
  606.       func->blin = 0;                  /* No more functions after that line  */
  607.    }
  608.  
  609.    return (OK);                        /* Ok seek for next function          */
  610. } /* LInfoFindNextFunc (); */
  611.  
  612.  
  613.  
  614.  
  615. int LInfoInclFuncInfo ( FILE *mapf, FILE *objf,
  616.                         funcTYPE *func, fposTYPE *fpos )
  617. /*
  618.     Function: Include all function info of specified function to mapfile.
  619.         Date: Mai, 19. 1993. 15:54. By LEL.
  620.    Interface: mapf = Mapfile of where to include the function info.
  621.               objf = Main objectfile.
  622.               func = Info about function.
  623.               fpos = Positions to blocks of data i main objecfile.
  624.      Returns: E/O.
  625.      Comment: Before this function return, the position of the file
  626.               'objf' will be restored back to the position it was before
  627.               this function was called.
  628.               But if any error, this function return without any
  629.               respect to the original position of main objectfile.
  630. */
  631. {
  632.    int      infyes    = 0;             /* Used to test if any general info   */
  633.    int      calyes    = 0;             /* Used to test if list of callers    */
  634.    int      anycaller = 0;             /* 1 if any caller of the function    */
  635.    long     oldpos;                    /* Original position of 'objf'        */
  636.    long     curpos;                    /* Current position of 'objf'         */
  637.    long     lnr;                       /* Linenumber of where call is done   */
  638.    char     fname [MAXFUNCN + 1];      /* Name of called function            */
  639.    char     oldcaller [MAXFUNCN + 1];  /* Name of previous caller            */
  640.    funcTYPE caller;                    /* Function which do the call         */
  641.  
  642.    oldcaller [0] = '\0';               /* Reset name of previous caller      */
  643.  
  644.    /*------------------------------------------------------------------------*/
  645.    if (o_lineinfo.c_ltot ||            /* If include of any general info     */
  646.        o_lineinfo.c_empl ||
  647.        o_lineinfo.c_coml ||
  648.        o_lineinfo.c_lcod ||
  649.        o_lineinfo.c_com)
  650.    {
  651.       infyes = 1;                      /* Remeber that some general info, yes*/
  652.    }
  653.  
  654.    if (o_lineinfo.calist)              /* If include list of callers         */
  655.    {
  656.       calyes = 1;                      /* Remember that list of callers, yes */
  657.    }
  658.  
  659.    if (!infyes && !calyes)             /* If neither gen. info nor callers   */
  660.    {
  661.       return (OK);                     /* Then do nothing but return         */
  662.    }
  663.  
  664.    if (o_various.gencom)               /* If generate comment blocks         */
  665.    {
  666.       WrtComStartLn (mapf);            /* Start block of comment             */
  667.    }
  668.    else
  669.    {
  670.       FPrintF (mapf, "\n");            /* Empty line rather than comment */
  671.    }
  672.  
  673.    if (errno != 0)                     /* Any error on last I/O's?           */
  674.    {
  675.       return (ERROR);
  676.    }
  677.  
  678.    /*------------------------------------------------------------------------*/
  679.    if (infyes)                         /* If include any general info        */
  680.    {
  681.       LInfoEmpty (mapf);               /* Tabulate into area of sourcecode   */
  682.  
  683.       /* Write header: General info...  */
  684.       FPrintF (mapf, "%s '%s ()':\n\n", _StrMSGGENERALFUNCINF, func->name);
  685.  
  686.       if (o_lineinfo.c_ltot)           /* If report total number of lines    */
  687.       {
  688.          LInfoEmpty (mapf);            /* Tabulate into area of sourcecode   */
  689.          FPrintF (mapf, "%s: %u\n", _StrMSGFUNCINF_LINTOT, func->lines);
  690.       }
  691.  
  692.       if (o_lineinfo.c_empl)           /* If report number of empty lines    */
  693.       {
  694.          LInfoEmpty (mapf);            /* Tabulate into area of sourcecode   */
  695.          FPrintF (mapf, "%s: %u\n", _StrMSGFUNCINF_LINEMP, func->empl);
  696.       }
  697.  
  698.       if (o_lineinfo.c_coml)           /* If report number of comment lines  */
  699.       {
  700.          LInfoEmpty (mapf);            /* Tabulate into area of sourcecode   */
  701.          FPrintF (mapf, "%s: %u\n", _StrMSGFUNCINF_LINCOM, func->coml);
  702.       }
  703.  
  704.       if (o_lineinfo.c_lcod)           /* If report number of lines with code*/
  705.       {
  706.          LInfoEmpty (mapf);            /* Tabulate into area of sourcecode   */
  707.          FPrintF (mapf, "%s: %u\n", _StrMSGFUNCINF_LINCOD, func->codl);
  708.       }
  709.  
  710.       if (o_lineinfo.c_com)            /* If report number of comment blocks */
  711.       {
  712.          LInfoEmpty (mapf);            /* Tabulate into area of sourcecode   */
  713.          FPrintF (mapf, "%s: %u\n", _StrMSGFUNCINF_CBLOCS, func->com);
  714.       }
  715.  
  716.       if (calyes)
  717.       {
  718.          FPrintF (mapf, "\n");         /* Empty line before list of callers */
  719.       }
  720.  
  721.       if (errno != 0)                  /* Any error on last I/O's?           */
  722.       {
  723.          return (ERROR);
  724.       }
  725.    }
  726.  
  727.    /*------------------------------------------------------------------------*/
  728.    if (calyes)
  729.    {
  730.       LInfoEmpty (mapf);               /* Tabulate into area of sourcecode   */
  731.  
  732.       /* Write header: List of callers... */
  733.       FPrintF (mapf, "%s '%s ()':\n\n", _StrMSGLISTOFCALLERS, func->name);
  734.  
  735.       oldpos = FTell (objf);           /* Remember original position of file */
  736.  
  737.       /* Start of datablock of function calls */
  738.       FSeek (objf, fpos->funcal, SEEK_SET);
  739.  
  740.       curpos = fpos->funcal;           /* Init current position controller   */
  741.       while (curpos < fpos->idlst)     /* Next datablock is identifiers      */
  742.       {
  743.          /* Read next sourceline from sourcefile */
  744.          FGetS0 (fname, MAXFUNCN, objf);
  745.  
  746.          if (errno != 0)               /* Any error on last I/O's?           */
  747.          {
  748.             return (ERROR);
  749.          }
  750.  
  751.          /* If call-name not equal func.name */
  752.          if (strcmp (fname, func->name) != 0)
  753.          {
  754.             while (1)                  /* Do a dummy seek past line numbers  */
  755.             {
  756.                /* Read next line number */
  757.                if (!FGetL (objf, &lnr))
  758.                {
  759.                   return (ERROR);
  760.                }
  761.  
  762.                if (lnr == 0L)          /* Any 0L terminate list of line nr.  */
  763.                   break;               /* So stop read of line numbers       */
  764.             }
  765.  
  766.             curpos = FTell (objf);     /* Update current position of file    */
  767.  
  768.             if (errno != 0)            /* Any error on last I/O's?           */
  769.             {
  770.                return (ERROR);
  771.             }
  772.  
  773.             continue;                  /* And continue read next call-name   */
  774.          }
  775.  
  776.          /* Now, we have found the block of calls to specified functionname
  777.             and the filepointer points to the line numbers of where each
  778.             call is done. Therefore, start read those line numbers, and
  779.             find which functions who own those lines.
  780.          */
  781.  
  782.          while (1)                     /* Loop through all line numbers */
  783.          {
  784.             if (!FGetL (objf, &lnr))   /* Read next line number */
  785.                return (ERROR);
  786.  
  787.             /* Any 0L terminates the list of line numbers */
  788.             if (lnr == 0L)
  789.                break;
  790.  
  791.             /* Which function own this line? If no function owns this line
  792.                then continue reading next. This should really never happen,
  793.                but in case... */
  794.             if (FuncRBuffLNrGet (lnr, &caller) == 0)
  795.                continue;
  796.  
  797.             /* Don't include same caller twice, so continue if not a
  798.                new caller */
  799.             if (strcmp (caller.name, oldcaller) == 0)
  800.                continue;
  801.  
  802.             /* Remember current caller, for next test */
  803.             strcpy (oldcaller, caller.name);
  804.  
  805.             anycaller = 1;             /* Now, at least one caller of func.  */
  806.  
  807.             LInfoEmpty (mapf);         /* Tabulate into area of sourcecode   */
  808.  
  809.             /* Name of function that do the call */
  810.             FPrintF (mapf, "%s ()\t%c-%ld\n",
  811.                            caller.name,
  812.                            prjstat.filc > 1 ? GLOBLINCHR : LOCLINCHR,
  813.                            caller.blin);
  814.  
  815.             if (errno != 0)            /* Any error on last I/O's?           */
  816.             {
  817.                return (ERROR);
  818.             }
  819.          }
  820.  
  821.          curpos = FTell (objf);        /* Update current position controller */
  822.  
  823.          if (errno != 0)               /* Any error on last I/O's?           */
  824.          {
  825.             return (ERROR);
  826.          }
  827.       }
  828.  
  829.       FSeek (objf, oldpos, SEEK_SET);  /* Restore to original position       */
  830.  
  831.       if (!anycaller)                  /* If no caller of that function      */
  832.       {
  833.          LInfoEmpty (mapf);            /* Tabulate into area of sourcecode   */
  834.          FPrintF (mapf, "%s\n", _StrMSGNOBODYCALLFUNC); /* No caller... */
  835.       }
  836.  
  837.       if (errno != 0)                  /* Any error on last I/O's?           */
  838.       {
  839.          return (ERROR);
  840.       }
  841.    }
  842.  
  843.    /*------------------------------------------------------------------------*/
  844.  
  845.    if (o_various.gencom)               /* If generate comment blocks         */
  846.    {
  847.       FPrintF (mapf, "*/\n");          /* Terminate block of comment         */
  848.    }
  849.    else
  850.    {
  851.       FPrintF (mapf, "\n");            /* Replace comment with empty line    */
  852.    }
  853.  
  854.    if (errno != 0)                     /* Any error on last I/O's?           */
  855.    {
  856.       return (ERROR);
  857.    }
  858.  
  859.    return (OK);                        /* OK include of function info        */
  860. } /* LInfoInclFuncInfo (); */
  861.  
  862.