1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  *      rep.c
  28  *
  29  *      This file handles the .nse_depinfo file
  30  */
  31 
  32 /*
  33  * Included files
  34  */ 
  35 #include <mk/defs.h>
  36 #include <mksh/misc.h>            /* retmem() */
  37 #include <vroot/report.h> /* NSE_DEPINFO */
  38 
  39 /*
  40  * Static variables
  41  */
  42 static  Recursive_make  recursive_list;
  43 static  Recursive_make  *bpatch = &recursive_list;
  44 static  Boolean         changed;
  45 
  46 /*
  47  * File table of contents
  48  */
  49 
  50 
  51 /*
  52  *      report_recursive_init()
  53  *
  54  *      Read the .nse_depinfo file and make a list of all the
  55  *      .RECURSIVE entries.
  56  *
  57  *      Parameters:
  58  *
  59  *      Static variables used:
  60  *              bpatch          Points to slot where next cell should be added
  61  *
  62  *      Global variables used:
  63  *              recursive_name  The Name ".RECURSIVE", compared against
  64  */
  65 
  66 void
  67 report_recursive_init(void)
  68 {
  69         char            *search_dir;
  70         char            nse_depinfo[MAXPATHLEN];
  71         FILE            *fp;
  72         int             line_size, line_index;
  73         wchar_t         *line;
  74         wchar_t         *bigger_line;
  75         wchar_t         *colon;
  76         wchar_t         *dollar; 
  77         Recursive_make  rp;
  78 
  79         /*
  80          * This routine can be called more than once,  don't do
  81          * anything after the first time.
  82          */
  83         if (depinfo_already_read) {
  84                 return;
  85         } else {
  86                 depinfo_already_read = true;
  87         }
  88                                         
  89         search_dir = getenv("NSE_DEP");
  90         if (search_dir == NULL) {
  91                 return;
  92         }
  93         (void) sprintf(nse_depinfo, "%s/%s", search_dir, NSE_DEPINFO);
  94         fp = fopen(nse_depinfo, "r");
  95         if (fp == NULL) {
  96                 return;
  97         }
  98         line_size = MAXPATHLEN;
  99         line_index = line_size - 1;
 100         line = ALLOC_WC(line_size);
 101         Wstring rns(recursive_name);
 102         wchar_t * wcb = rns.get_string();
 103         while (fgetws(line, line_size, fp) != NULL) {
 104                 while (wslen(line) == line_index) {
 105                         if (line[wslen(line) - 1] == '\n') {
 106                                 continue;
 107                         }
 108                         bigger_line = ALLOC_WC(2 * line_size);
 109                         wscpy(bigger_line, line);
 110                         retmem(line);
 111                         line = bigger_line;
 112                         if (fgetws(&line[line_index], line_size, fp) == NULL)
 113                                 continue;
 114                         line_index = 2 * line_index;
 115                         line_size = 2 * line_size;
 116                 }
 117 
 118                 colon = (wchar_t *) wschr(line, (int) colon_char);
 119                 if (colon == NULL) {
 120                         continue;
 121                 }
 122                 dollar = (wchar_t *) wschr(line, (int) dollar_char);
 123                 line[wslen(line) - 1] = (int) nul_char;
 124                 if (IS_WEQUALN(&colon[2], wcb,
 125                     (int) recursive_name->hash.length)) {
 126                         /*
 127                          * If this entry is an old entry, ignore it
 128                          */
 129                         MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
 130                         if (dollar == NULL ||
 131                             !IS_WEQUALN(wcs_buffer, (dollar+1) - VER_LEN, VER_LEN)){
 132                                 continue;
 133                             }
 134                         rp = ALLOC(Recursive_make);
 135                         (void) memset((char *) rp, 0, sizeof (Recursive_make_rec));
 136                         /*
 137                          * set conditional_macro_string if string is present
 138                          */
 139                         rp->oldline = (wchar_t *) wsdup(line);
 140                         if ( dollar != NULL ){
 141                                 rp->cond_macrostring = 
 142                                     (wchar_t *) wsdup(dollar - VER_LEN + 1);
 143                         }
 144                         /* 
 145                          * get target name into recursive struct
 146                          */
 147                         *colon = (int) nul_char;
 148                         rp->target = (wchar_t *) wsdup(line);
 149                         *bpatch = rp;
 150                         bpatch = &rp->next;
 151                 }
 152         }
 153         (void) fclose(fp);
 154 }
 155 
 156 /*
 157  *      report_recursive_dep(target, line)
 158  *
 159  *      Report a target as recursive.
 160  *
 161  *      Parameters:
 162  *              line            Dependency line reported
 163  *
 164  *      Static variables used:
 165  *              bpatch          Points to slot where next cell should be added
 166  *              changed         Written if report set changed
 167  */
 168 void
 169 report_recursive_dep(Name target, wchar_t *line)
 170 {
 171         Recursive_make  rp;
 172         wchar_t         rec_buf[STRING_BUFFER_LENGTH];
 173         String_rec      string;
 174 
 175         INIT_STRING_FROM_STACK(string, rec_buf);
 176         cond_macros_into_string(target, &string);
 177         /* 
 178          * find an applicable recursive entry, if there isn't one, create it
 179          */
 180         rp = find_recursive_target(target);
 181         if (rp == NULL) {
 182                 rp = ALLOC(Recursive_make);
 183                 (void) memset((char *) rp, 0, sizeof (Recursive_make_rec));
 184                 wchar_t * wcb = get_wstring(target->string_mb); // XXX Tolik: needs retmem
 185                 rp->target = wcb;
 186                 rp->newline = (wchar_t *) wsdup(line);
 187                 rp->cond_macrostring = (wchar_t *) wsdup(rec_buf);
 188                 *bpatch = rp;
 189                 bpatch = &rp->next;
 190                 changed = true;
 191         } else {
 192                 if ((rp->oldline != NULL) && !IS_WEQUAL(rp->oldline, line)) {
 193                         rp->newline = (wchar_t *) wsdup(line);
 194                         changed = true;
 195                 }
 196                 rp->removed = false;
 197         }
 198 }
 199 
 200 /*
 201  *      find_recursive_target(target)
 202  *
 203  *      Search the list for a given target.
 204  *
 205  *      Return value:
 206  *                              The target cell
 207  *
 208  *      Parameters:
 209  *              target          The target we need
 210  *              top_level_target more info used to determinde the 
 211  *                               target we need
 212  *
 213  *      Static variables used:
 214  *              recursive_list  The list of targets
 215  */
 216 Recursive_make
 217 find_recursive_target(Name target)
 218 {
 219         Recursive_make  rp;
 220         String_rec      string;
 221         wchar_t         rec_buf[STRING_BUFFER_LENGTH]; 
 222 
 223         INIT_STRING_FROM_STACK(string, rec_buf);
 224         cond_macros_into_string(target, &string);
 225 
 226         Wstring tstr(target);
 227         wchar_t * wcb = tstr.get_string();
 228         for (rp = recursive_list; rp != NULL; rp = rp->next) {
 229                 /* 
 230                  * If this entry has already been removed, ignore it.
 231                  */
 232                 if (rp->removed)
 233                         continue;
 234                 /* 
 235                  * If this target, and the target on the list are the same
 236                  * and if one of them contains conditional macro info, while
 237                  * the other doesn't,  remove this entry from the list of
 238                  * recursive entries.  This can only happen if the Makefile
 239                  * has changed to no longer contain conditional macros.
 240                  */
 241                 if (IS_WEQUAL(rp->target, wcb)) {
 242                         if (rp->cond_macrostring[VER_LEN] == '\0' &&
 243                             string.buffer.start[VER_LEN] != '\0'){
 244                                 rp->removed = true;
 245                                 continue;
 246                         } else if (rp->cond_macrostring[VER_LEN] != '\0' &&
 247                             string.buffer.start[VER_LEN] == '\0'){
 248                                 rp->removed = true;
 249                                 continue;
 250                         } 
 251                 }
 252                 /*
 253                  * If this is not a VERS2 entry,  only need to match
 254                  * the target name.  toptarg information from VERS1 entries
 255                  * are ignored.
 256                  */
 257                 MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
 258                 if (IS_WEQUALN(wcs_buffer, string.buffer.start, VER_LEN)) { 
 259                         if (IS_WEQUAL(rp->cond_macrostring, 
 260                             string.buffer.start) &&
 261                             IS_WEQUAL(rp->target, wcb)) {
 262                                 return rp;
 263                         }
 264                 } else {
 265                         if (IS_WEQUAL(rp->target, wcb)) {
 266                                 return rp;
 267                         }
 268                 }
 269         }
 270         return NULL;
 271 }
 272 
 273 /*
 274  *      remove_recursive_dep(target, top_level_target)
 275  *
 276  *      Mark a target as no longer recursive.
 277  *
 278  *      Parameters:
 279  *              target          The target we want to remove
 280  *              top_level_target target we want to remove must be built from 
 281  *                               the same top level target
 282  *
 283  *      Static variables used:
 284  *              changed         Written if report set changed
 285  */
 286 void
 287 remove_recursive_dep(Name target)
 288 {
 289         Recursive_make  rp;
 290 
 291         rp = find_recursive_target(target);
 292 
 293         if ( rp != NULL ) {
 294                 rp->removed = true;  
 295                 changed = true;
 296                 if(rp->target) {
 297                         retmem(rp->target);
 298                         rp->target = NULL;
 299                 }
 300                 if(rp->newline) {
 301                         retmem(rp->newline);
 302                         rp->newline = NULL;
 303                 }
 304                 if(rp->oldline) {
 305                         retmem(rp->oldline);
 306                         rp->oldline = NULL;
 307                 }
 308                 if(rp->cond_macrostring) {
 309                         retmem(rp->cond_macrostring);
 310                         rp->cond_macrostring = NULL;
 311                 }
 312         }
 313 }
 314 
 315 
 316 /* gather_recursive_deps()
 317  *
 318  *      Create or update list of recursive targets.  
 319  */
 320 void
 321 gather_recursive_deps(void)
 322 {
 323         Name_set::iterator      np, e;
 324         String_rec              rec;
 325         wchar_t                 rec_buf[STRING_BUFFER_LENGTH];
 326         register Property       lines;
 327         Boolean                 has_recursive;
 328         Dependency              dp;
 329 
 330         report_recursive_init();
 331 
 332         /* Go thru all targets and dump recursive dependencies */
 333         for (np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
 334                 if (np->has_recursive_dependency){
 335                         has_recursive = false;
 336                         /* 
 337                          * start .RECURSIVE line with target:
 338                          */
 339                         INIT_STRING_FROM_STACK(rec, rec_buf);
 340                         APPEND_NAME(np, &rec, FIND_LENGTH);
 341                         append_char((int) colon_char, &rec);
 342                         append_char((int) space_char, &rec);
 343                         
 344                         for (lines = get_prop(np->prop,recursive_prop); 
 345                             lines != NULL;
 346                             lines = get_prop(lines->next, recursive_prop)) {
 347                                 /* 
 348                                  * if entry is already in depinfo
 349                                  * file or entry was not built, ignore it
 350                                  */
 351                                 if (lines->body.recursive.in_depinfo)
 352                                         continue;
 353                                 if (!lines->body.recursive.has_built)
 354                                         continue;
 355                                 has_recursive = true;
 356                                 lines->body.recursive.in_depinfo=true;
 357                                 
 358                                 /* 
 359                                 * Write the remainder of the
 360                                 * .RECURSIVE line 
 361                                 */
 362                                 APPEND_NAME(recursive_name, &rec, 
 363                                     FIND_LENGTH);
 364                                 append_char((int) space_char, &rec);
 365                                 APPEND_NAME(lines->body.recursive.directory,
 366                                         &rec, FIND_LENGTH);
 367                                 append_char((int) space_char, &rec);
 368                                 APPEND_NAME(lines->body.recursive.target,
 369                                         &rec, FIND_LENGTH);
 370                                 append_char((int) space_char, &rec);
 371                                 
 372                                 /* Complete list of makefiles used */
 373                                 for (dp = lines->body.recursive.makefiles; 
 374                                     dp != NULL; 
 375                                     dp = dp->next) {
 376                                         APPEND_NAME(dp->name, &rec,  FIND_LENGTH);
 377                                         append_char((int) space_char, &rec);
 378                                 }
 379                         }  
 380                         /* 
 381                          * dump list of conditional targets,
 382                          * and report recursive entry, if needed
 383                          */
 384                         cond_macros_into_string(np, &rec);
 385                         if (has_recursive){
 386                                 report_recursive_dep(np, rec.buffer.start);
 387                         }
 388 
 389                 } else if ( np->has_built ) {
 390                         remove_recursive_dep(np);
 391                 }
 392         }
 393 }
 394