1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: projecttool.c
6  * Project management tool
7  * Written by: Steven M. Rubin
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "config.h"
33 #if PROJECTTOOL
34 
35 #include "global.h"
36 #include "projecttool.h"
37 #include "database.h"
38 #include "edialogs.h"
39 #include "usr.h"
40 #include "usrdiacom.h"
41 #include "tecgen.h"
42 
43 /***** command parsing *****/
44 
45 static COMCOMP projcop = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
46 	INPUTOPT, x_(" \t"), M_("cell to be checked-out"), M_("check-out current cell")};
47 static COMCOMP projcip = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
48 	INPUTOPT, x_(" \t"), M_("cell to be checked-in"), M_("check-in current cell")};
49 static COMCOMP projoldp = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
50 	INPUTOPT, x_(" \t"), M_("cell from which old version should be retrieved"),
51 		M_("use current cell")};
52 static COMCOMP projap = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
53 	INPUTOPT, x_(" \t"), M_("cell to be added"), M_("add current cell")};
54 static COMCOMP projdp = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
55 	INPUTOPT, x_(" \t"), M_("cell to be deleted"), M_("delete current cell")};
56 static KEYWORD projopt[] =
57 {
58 	{x_("build-project"),        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
59 	{x_("check-out"),            1,{&projcop,NOKEY,NOKEY,NOKEY,NOKEY}},
60 	{x_("check-in"),             1,{&projcip,NOKEY,NOKEY,NOKEY,NOKEY}},
61 	{x_("get-old-version"),      1,{&projoldp,NOKEY,NOKEY,NOKEY,NOKEY}},
62 	{x_("add-cell"),             1,{&projap,NOKEY,NOKEY,NOKEY,NOKEY}},
63 	{x_("delete-cell"),          1,{&projdp,NOKEY,NOKEY,NOKEY,NOKEY}},
64 	{x_("update"),               0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
65 	{x_("set-user"),             0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
66 	{x_("list-cells"),           0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
67 	TERMKEY
68 };
69 COMCOMP proj_projp = {projopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
70 	0, x_(" \t"), M_("Project management tool action"), x_("")};
71 
72 /***** cell checking queue *****/
73 
74 #define NOFCHECK ((FCHECK *)-1)
75 
76 typedef struct Ifcheck
77 {
78 	NODEPROTO      *entry;
79 	INTBIG          batchnumber;
80 	struct Ifcheck *nextfcheck;
81 } FCHECK;
82 
83 static FCHECK *proj_firstfcheck = NOFCHECK;
84 static FCHECK *proj_fcheckfree = NOFCHECK;
85 
86 /***** user database information *****/
87 
88 #define NOPUSER ((PUSER *)-1)
89 #define PUSERFILE x_("projectusers")
90 
91 typedef struct Ipuser
92 {
93 	CHAR *username;
94 	CHAR *userpassword;
95 	struct Ipuser *nextpuser;
96 } PUSER;
97 
98 static PUSER *proj_users = NOPUSER;
99 
100 /***** project file information *****/
101 
102 #define NOPROJECTCELL ((PROJECTCELL *)-1)
103 
104 typedef struct Iprojectcell
105 {
106 	CHAR  *libname;						/* name of the library */
107 	CHAR  *cellname;					/* name of the cell */
108 	VIEW  *cellview;					/* cell view */
109 	INTBIG cellversion;					/* cell version */
110 	CHAR  *owner;						/* current owner of this cell (if checked out) */
111 	CHAR  *lastowner;					/* previous owner of this cell (if checked in) */
112 	CHAR  *comment;						/* comments for this cell */
113 	struct Iprojectcell *nextprojectcell;
114 } PROJECTCELL;
115 
116 static PROJECTCELL *proj_firstprojectcell = NOPROJECTCELL;
117 static PROJECTCELL *proj_projectcellfree = NOPROJECTCELL;
118 
119 /***** miscellaneous *****/
120 
121 static TOOL         *proj_tool;					/* this tool */
122 static CHAR          proj_username[256];		/* current user's name */
123 static INTBIG        proj_lockedkey;			/* key for "PROJ_locked" */
124 static INTBIG        proj_pathkey;				/* key for "PROJ_path" */
125 static INTBIG        proj_userkey;				/* key for "PROJ_user" */
126 static BOOLEAN       proj_active;				/* nonzero if the system is active */
127 static BOOLEAN       proj_ignorechanges;		/* nonzero to ignore broadcast changes */
128 static TOOL         *proj_source;				/* source of changes */
129 static INTBIG        proj_batchnumber;			/* ID number of this batch of changes */
130 static PUSER        *proj_userpos;				/* current user for dialog display */
131 static FILE         *proj_io;					/* channel to project file */
132 static INTBIG       *proj_savetoolstate = 0;	/* saved tool state information */
133 static INTBIG        proj_filetypeproj;			/* Project disk file descriptor */
134 static INTBIG        proj_filetypeprojusers;	/* Project users disk file descriptor */
135 
136 /* prototypes for local routines */
137 static void          proj_addcell(CHAR *cellname);
138 static FCHECK       *proj_allocfcheck(void);
139 static PROJECTCELL  *proj_allocprojectcell(void);
140 static void          proj_buildproject(LIBRARY *lib);
141 static void          proj_checkin(CHAR *cellname);
142 static void          proj_checkinmany(LIBRARY *lib);
143 static void          proj_checkout(CHAR *cellname, BOOLEAN showcell);
144 static void          proj_deletecell(CHAR *cellname);
145 static void          proj_endwritingprojectfile(void);
146 static PROJECTCELL  *proj_findcell(NODEPROTO *np);
147 static void          proj_freefcheck(FCHECK *f);
148 static void          proj_freeprojectcell(PROJECTCELL *pf);
149 static BOOLEAN       proj_getcomments(PROJECTCELL *pf, CHAR *direction);
150 static NODEPROTO    *proj_getcell(PROJECTCELL *pf, LIBRARY *lib);
151 static void          proj_getoldversion(CHAR *cellname);
152 static BOOLEAN       proj_getprojinfo(LIBRARY *lib, CHAR *path, CHAR *projfile);
153 static BOOLEAN       proj_getusername(BOOLEAN newone, LIBRARY *lib);
154 static BOOLEAN       proj_initusers(CHAR **c);
155 static BOOLEAN       proj_loadlist(LIBRARY *lib, void *dia);
156 static BOOLEAN       proj_lockprojfile(CHAR *projectpath, CHAR *projectfile);
157 static void          proj_marklocked(NODEPROTO *np, BOOLEAN locked);
158 static CHAR         *proj_nextuser(void);
159 static void          proj_queuecheck(NODEPROTO *cell);
160 static BOOLEAN       proj_readprojectfile(CHAR *pathname, CHAR *filename);
161 static void          proj_restoretoolstate(void);
162 static void          proj_showlistdialog(LIBRARY *lib);
163 static BOOLEAN       proj_startwritingprojectfile(CHAR *pathname, CHAR *filename);
164 static CHAR         *proj_templibraryname(void);
165 static BOOLEAN       proj_turnofftools(void);
166 static void          proj_unlockprojfile(CHAR *projectpath, CHAR *projectfile);
167 static void          proj_update(LIBRARY *lib);
168 static BOOLEAN       proj_usenewestversion(NODEPROTO *oldnp, NODEPROTO *newnp);
169 static void          proj_validatelocks(LIBRARY *lib);
170 static CHAR         *proj_wantpassword(INTBIG mode, CHAR *username);
171 static BOOLEAN       proj_writecell(NODEPROTO *np);
172 
173 /* prototypes for local routines that should be in the system */
174 static NODEPROTO    *copyrecursively(NODEPROTO *fromnp, LIBRARY *tolib);
175 static NODEPROTO    *copyskeleton(NODEPROTO *fromnp, LIBRARY *tolib);
176 
177 /************************ CONTROL ***********************/
178 
proj_init(INTBIG * argc,CHAR1 * argv[],TOOL * thistool)179 void proj_init(INTBIG *argc, CHAR1 *argv[], TOOL *thistool)
180 {
181 	/* ignore pass 3 initialization */
182 	if (thistool == 0) return;
183 
184 	/* miscellaneous initialization during pass 2 */
185 	if (thistool == NOTOOL)
186 	{
187 		proj_lockedkey = makekey(x_("PROJ_locked"));
188 		proj_pathkey = makekey(x_("PROJ_path"));
189 		proj_userkey = makekey(x_("PROJ_user"));
190 		proj_username[0] = 0;
191 		proj_active = FALSE;
192 		proj_ignorechanges = FALSE;
193 		proj_filetypeproj = setupfiletype(x_(""), x_("*.*"), MACFSTAG('TEXT'), FALSE, x_("proj"), _("Project"));
194 		proj_filetypeprojusers = setupfiletype(x_(""), x_("*.*"), MACFSTAG('TEXT'), FALSE, x_("projusers"), _("Project Users"));
195 		return;
196 	}
197 
198 	/* copy tool pointer during pass 1 */
199 	proj_tool = thistool;
200 }
201 
proj_done(void)202 void proj_done(void)
203 {
204 #ifdef DEBUGMEMORY
205 	REGISTER FCHECK *f;
206 	REGISTER PROJECTCELL *pf;
207 	REGISTER PUSER *pu;
208 
209 	while (proj_users != NOPUSER)
210 	{
211 		pu = proj_users;
212 		proj_users = proj_users->nextpuser;
213 		efree((CHAR *)pu->username);
214 		efree((CHAR *)pu->userpassword);
215 		efree((CHAR *)pu);
216 	}
217 
218 	while (proj_firstprojectcell != NOPROJECTCELL)
219 	{
220 		pf = proj_firstprojectcell;
221 		proj_firstprojectcell = proj_firstprojectcell->nextprojectcell;
222 		efree(pf->libname);
223 		efree(pf->cellname);
224 		efree(pf->owner);
225 		efree(pf->lastowner);
226 		efree(pf->comment);
227 		proj_freeprojectcell(pf);
228 	}
229 	while (proj_projectcellfree != NOPROJECTCELL)
230 	{
231 		pf = proj_projectcellfree;
232 		proj_projectcellfree = proj_projectcellfree->nextprojectcell;
233 		efree((CHAR *)pf);
234 	}
235 
236 	while (proj_firstfcheck != NOFCHECK)
237 	{
238 		f = proj_firstfcheck;
239 		proj_firstfcheck = proj_firstfcheck->nextfcheck;
240 		proj_freefcheck(f);
241 	}
242 	while (proj_fcheckfree != NOFCHECK)
243 	{
244 		f = proj_fcheckfree;
245 		proj_fcheckfree = proj_fcheckfree->nextfcheck;
246 		efree((CHAR *)f);
247 	}
248 	if (proj_savetoolstate != 0)
249 		efree((CHAR *)proj_savetoolstate);
250 #endif
251 }
252 
proj_slice(void)253 void proj_slice(void)
254 {
255 	REGISTER FCHECK *f, *nextf;
256 	REGISTER NODEPROTO *np;
257 	TOOL *tool;
258 	REGISTER INTBIG lowbatch, highbatch, retval, undonecells;
259 	REGISTER void *infstr;
260 
261 	if (!proj_active) return;
262 	if (proj_firstfcheck == NOFCHECK) return;
263 
264 	undonecells = 0;
265 	for(f = proj_firstfcheck; f != NOFCHECK; f = nextf)
266 	{
267 		nextf = f->nextfcheck;
268 		np = f->entry;
269 
270 		/* make sure cell np is checked-out */
271 		if (getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, proj_lockedkey) != NOVARIABLE)
272 		{
273 			if (undonecells == 0)
274 			{
275 				infstr = initinfstr();
276 				lowbatch = highbatch = f->batchnumber;
277 			} else
278 			{
279 				if (f->batchnumber < lowbatch) lowbatch = f->batchnumber;
280 				if (f->batchnumber > highbatch) highbatch = f->batchnumber;
281 				addstringtoinfstr(infstr, x_(", "));
282 			}
283 			addstringtoinfstr(infstr, describenodeproto(np));
284 			undonecells++;
285 		}
286 		proj_freefcheck(f);
287 	}
288 	proj_firstfcheck = NOFCHECK;
289 	if (undonecells > 0)
290 	{
291 		ttyputerr(_("Cannot change unchecked-out %s: %s"),
292 			makeplural(_("cell"), undonecells),
293 			returninfstr(infstr));
294 		proj_ignorechanges = TRUE;
295 		for(;;)
296 		{
297 			retval = undoabatch(&tool);
298 			if (retval == 0) break;
299 			if (retval < 0) retval = -retval;
300 			if (retval <= lowbatch) break;
301 		}
302 		noredoallowed();
303 		proj_ignorechanges = FALSE;
304 	}
305 }
306 
proj_set(INTBIG count,CHAR * par[])307 void proj_set(INTBIG count, CHAR *par[])
308 {
309 	REGISTER INTBIG l;
310 	REGISTER CHAR *pp, *cellname;
311 	REGISTER NODEPROTO *np;
312 
313 	if (count <= 0)
314 	{
315 		ttyputerr(_("Missing command to display tool"));
316 		return;
317 	}
318 	l = estrlen(pp = par[0]);
319 	if (namesamen(pp, x_("add-cell"), l) == 0)
320 	{
321 		if (count >= 2) cellname = par[1]; else
322 		{
323 			np = getcurcell();
324 			if (np == NONODEPROTO)
325 			{
326 				ttyputerr(_("No current cell to add"));
327 				return;
328 			}
329 			cellname = describenodeproto(np);
330 		}
331 		proj_addcell(cellname);
332 		proj_active = TRUE;
333 		return;
334 	}
335 	if (namesamen(pp, x_("build-project"), l) == 0)
336 	{
337 		if (el_curlib == NOLIBRARY)
338 		{
339 			ttyputerr(_("No current library to enter"));
340 			return;
341 		}
342 		proj_buildproject(el_curlib);
343 		proj_active = TRUE;
344 		return;
345 	}
346 	if (namesamen(pp, x_("check-in"), l) == 0 && l >= 7)
347 	{
348 		if (count >= 2) cellname = par[1]; else
349 		{
350 			np = getcurcell();
351 			if (np == NONODEPROTO)
352 			{
353 				ttyputerr(_("No current cell to check in"));
354 				return;
355 			}
356 			cellname = describenodeproto(np);
357 		}
358 		proj_checkin(cellname);
359 		proj_active = TRUE;
360 		return;
361 	}
362 	if (namesamen(pp, x_("check-out"), l) == 0 && l >= 7)
363 	{
364 		if (count >= 2) cellname = par[1]; else
365 		{
366 			np = getcurcell();
367 			if (np == NONODEPROTO)
368 			{
369 				ttyputerr(_("No current cell to check out"));
370 				return;
371 			}
372 			cellname = describenodeproto(np);
373 		}
374 		proj_checkout(cellname, TRUE);
375 		proj_active = TRUE;
376 		return;
377 	}
378 	if (namesamen(pp, x_("delete-cell"), l) == 0)
379 	{
380 		if (count >= 2) cellname = par[1]; else
381 		{
382 			np = getcurcell();
383 			if (np == NONODEPROTO)
384 			{
385 				ttyputerr(_("No current cell to delete"));
386 				return;
387 			}
388 			cellname = describenodeproto(np);
389 		}
390 		proj_deletecell(cellname);
391 		proj_active = TRUE;
392 		return;
393 	}
394 	if (namesamen(pp, x_("get-old-version"), l) == 0)
395 	{
396 		if (count >= 2) cellname = par[1]; else
397 		{
398 			np = getcurcell();
399 			if (np == NONODEPROTO)
400 			{
401 				ttyputerr(_("No current cell to retrieve old versions"));
402 				return;
403 			}
404 			cellname = describenodeproto(np);
405 		}
406 		proj_getoldversion(cellname);
407 		proj_active = TRUE;
408 		return;
409 	}
410 	if (namesamen(pp, x_("list-cells"), l) == 0)
411 	{
412 		proj_showlistdialog(el_curlib);
413 		return;
414 	}
415 	if (namesamen(pp, x_("set-user"), l) == 0)
416 	{
417 		(void)proj_getusername(TRUE, el_curlib);
418 		return;
419 	}
420 	if (namesamen(pp, x_("update"), l) == 0)
421 	{
422 		if (el_curlib == NOLIBRARY)
423 		{
424 			ttyputerr(_("No current library to update"));
425 			return;
426 		}
427 		proj_update(el_curlib);
428 		proj_active = TRUE;
429 		return;
430 	}
431 }
432 
proj_startbatch(TOOL * source,BOOLEAN undoredo)433 void proj_startbatch(TOOL *source, BOOLEAN undoredo)
434 {
435 	/* code cannot be called by multiple procesors: uses globals */
436 	NOT_REENTRANT;
437 
438 	if (proj_ignorechanges) proj_source = proj_tool; else
439 		proj_source = source;
440 	proj_batchnumber = getcurrentbatchnumber();
441 }
442 
proj_modifynodeinst(NODEINST * ni,INTBIG olx,INTBIG oly,INTBIG ohx,INTBIG ohy,INTBIG orot,INTBIG otran)443 void proj_modifynodeinst(NODEINST *ni, INTBIG olx, INTBIG oly, INTBIG ohx, INTBIG ohy,
444 	INTBIG orot, INTBIG otran)
445 {
446 	if (proj_ignorechanges || proj_source == proj_tool) return;
447 	proj_queuecheck(ni->parent);
448 }
449 
proj_modifyarcinst(ARCINST * ai,INTBIG oxA,INTBIG oyA,INTBIG oxB,INTBIG oyB,INTBIG owid,INTBIG olen)450 void proj_modifyarcinst(ARCINST *ai, INTBIG oxA, INTBIG oyA, INTBIG oxB, INTBIG oyB,
451 	INTBIG owid, INTBIG olen)
452 {
453 	if (proj_ignorechanges || proj_source == proj_tool) return;
454 	proj_queuecheck(ai->parent);
455 }
456 
proj_modifyportproto(PORTPROTO * pp,NODEINST * oni,PORTPROTO * opp)457 void proj_modifyportproto(PORTPROTO *pp, NODEINST *oni, PORTPROTO *opp)
458 {
459 	if (proj_ignorechanges || proj_source == proj_tool) return;
460 	proj_queuecheck(pp->parent);
461 }
462 
proj_modifydescript(INTBIG addr,INTBIG type,INTBIG key,UINTBIG * old)463 void proj_modifydescript(INTBIG addr, INTBIG type, INTBIG key, UINTBIG *old)
464 {
465 	if (proj_ignorechanges || proj_source == proj_tool) return;
466 	switch (type&VTYPE)
467 	{
468 		case VNODEINST:  proj_queuecheck(((NODEINST *)addr)->parent);   break;
469 		case VARCINST:   proj_queuecheck(((ARCINST *)addr)->parent);    break;
470 		case VPORTPROTO: proj_queuecheck(((PORTPROTO *)addr)->parent);  break;
471 	}
472 }
473 
proj_newobject(INTBIG addr,INTBIG type)474 void proj_newobject(INTBIG addr, INTBIG type)
475 {
476 	if (proj_ignorechanges || proj_source == proj_tool) return;
477 	switch (type&VTYPE)
478 	{
479 		case VNODEINST:  proj_queuecheck(((NODEINST *)addr)->parent);   break;
480 		case VARCINST:   proj_queuecheck(((ARCINST *)addr)->parent);    break;
481 		case VPORTPROTO: proj_queuecheck(((PORTPROTO *)addr)->parent);  break;
482 	}
483 }
484 
proj_killobject(INTBIG addr,INTBIG type)485 void proj_killobject(INTBIG addr, INTBIG type)
486 {
487 	if (proj_ignorechanges || proj_source == proj_tool) return;
488 	switch (type&VTYPE)
489 	{
490 		case VNODEINST:  proj_queuecheck(((NODEINST *)addr)->parent);   break;
491 		case VARCINST:   proj_queuecheck(((ARCINST *)addr)->parent);    break;
492 		case VPORTPROTO: proj_queuecheck(((PORTPROTO *)addr)->parent);  break;
493 	}
494 }
495 
proj_newvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG newtype)496 void proj_newvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG newtype)
497 {
498 	if (proj_ignorechanges || proj_source == proj_tool) return;
499 	switch (type&VTYPE)
500 	{
501 		case VNODEINST:  proj_queuecheck(((NODEINST *)addr)->parent);   break;
502 		case VARCINST:   proj_queuecheck(((ARCINST *)addr)->parent);    break;
503 		case VPORTPROTO: proj_queuecheck(((PORTPROTO *)addr)->parent);  break;
504 		case VNODEPROTO:
505 			if (key != proj_lockedkey) proj_queuecheck((NODEPROTO *)addr);
506 			break;
507 	}
508 }
509 
proj_killvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG oldaddr,INTBIG oldtype,UINTBIG * olddescript)510 void proj_killvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG oldaddr, INTBIG oldtype,
511 	UINTBIG *olddescript)
512 {
513 	if (proj_ignorechanges || proj_source == proj_tool) return;
514 	switch (type&VTYPE)
515 	{
516 		case VNODEINST:  proj_queuecheck(((NODEINST *)addr)->parent);   break;
517 		case VARCINST:   proj_queuecheck(((ARCINST *)addr)->parent);    break;
518 		case VPORTPROTO: proj_queuecheck(((PORTPROTO *)addr)->parent);  break;
519 		case VNODEPROTO:
520 			if (key != proj_lockedkey) proj_queuecheck((NODEPROTO *)addr);
521 			break;
522 	}
523 }
524 
proj_modifyvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG vartype,INTBIG aindex,INTBIG oldvalue)525 void proj_modifyvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG vartype,
526 	INTBIG aindex, INTBIG oldvalue)
527 {
528 	if (proj_ignorechanges || proj_source == proj_tool) return;
529 	switch (type&VTYPE)
530 	{
531 		case VNODEINST:  proj_queuecheck(((NODEINST *)addr)->parent);   break;
532 		case VARCINST:   proj_queuecheck(((ARCINST *)addr)->parent);    break;
533 		case VPORTPROTO: proj_queuecheck(((PORTPROTO *)addr)->parent);  break;
534 		case VNODEPROTO: proj_queuecheck((NODEPROTO *)addr);            break;
535 	}
536 }
537 
proj_insertvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG vartype,INTBIG index)538 void proj_insertvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG vartype, INTBIG index)
539 {
540 	if (proj_ignorechanges || proj_source == proj_tool) return;
541 	switch (type&VTYPE)
542 	{
543 		case VNODEINST:  proj_queuecheck(((NODEINST *)addr)->parent);   break;
544 		case VARCINST:   proj_queuecheck(((ARCINST *)addr)->parent);    break;
545 		case VPORTPROTO: proj_queuecheck(((PORTPROTO *)addr)->parent);  break;
546 		case VNODEPROTO: proj_queuecheck((NODEPROTO *)addr);            break;
547 	}
548 }
549 
proj_deletevariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG vartype,INTBIG index,INTBIG oldvalue)550 void proj_deletevariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG vartype, INTBIG index,
551 	INTBIG oldvalue)
552 {
553 	if (proj_ignorechanges || proj_source == proj_tool) return;
554 	switch (type&VTYPE)
555 	{
556 		case VNODEINST:  proj_queuecheck(((NODEINST *)addr)->parent);   break;
557 		case VARCINST:   proj_queuecheck(((ARCINST *)addr)->parent);    break;
558 		case VPORTPROTO: proj_queuecheck(((PORTPROTO *)addr)->parent);  break;
559 		case VNODEPROTO: proj_queuecheck((NODEPROTO *)addr);            break;
560 	}
561 }
562 
proj_readlibrary(LIBRARY * lib)563 void proj_readlibrary(LIBRARY *lib)
564 {
565 	REGISTER NODEPROTO *np;
566 
567 	/* scan the library to see if any cells are locked */
568 	if (proj_ignorechanges) return;
569 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
570 	{
571 		if (getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, proj_lockedkey) != NOVARIABLE)
572 			proj_active = TRUE;
573 	}
574 }
575 
576 /************************ PROJECT MANAGEMENT ***********************/
577 
proj_checkin(CHAR * cellname)578 void proj_checkin(CHAR *cellname)
579 {
580 	REGISTER NODEPROTO *np, *onp;
581 	REGISTER NODEINST *ni;
582 	REGISTER INTBIG total;
583 	REGISTER BOOLEAN propagated;
584 	REGISTER LIBRARY *olib;
585 	REGISTER PROJECTCELL *pf;
586 	REGISTER void *infstr;
587 
588 	/* find out which cell is being checked in */
589 	np = getnodeproto(cellname);
590 	if (np == NONODEPROTO)
591 	{
592 		ttyputerr(_("Cannot identify cell '%s'"), cellname);
593 		return;
594 	}
595 
596 	/* mark the cell to be checked-in */
597 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
598 		for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
599 			onp->temp1 = 0;
600 	np->temp1 = 1;
601 
602 	/* look for cells above this one that must also be checked in */
603 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
604 		for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
605 			onp->temp2 = 0;
606 	np->temp2 = 1;
607 	propagated = TRUE;
608 	while (propagated)
609 	{
610 		propagated = FALSE;
611 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
612 			for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
613 		{
614 			if (onp->temp2 == 1)
615 			{
616 				propagated = TRUE;
617 				onp->temp2 = 2;
618 				for(ni = onp->firstinst; ni != NONODEINST; ni = ni->nextinst)
619 				{
620 					if (ni->parent->temp2 == 0) ni->parent->temp2 = 1;
621 				}
622 			}
623 		}
624 	}
625 	np->temp2 = 0;
626 	total = 0;
627 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
628 		for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
629 	{
630 		if (onp->temp2 == 0) continue;
631 		pf = proj_findcell(onp);
632 		if (pf == NOPROJECTCELL) continue;
633 		if (namesame(pf->owner, proj_username) == 0)
634 		{
635 			onp->temp1 = 1;
636 			total++;
637 		}
638 	}
639 
640 	/* look for cells below this one that must also be checked in */
641 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
642 		for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
643 			onp->temp2 = 0;
644 	np->temp2 = 1;
645 	propagated = TRUE;
646 	while (propagated)
647 	{
648 		propagated = FALSE;
649 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
650 			for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
651 		{
652 			if (onp->temp2 == 1)
653 			{
654 				propagated = TRUE;
655 				onp->temp2 = 2;
656 				for(ni = onp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
657 				{
658 					if (ni->proto->primindex != 0) continue;
659 					if (ni->proto->temp2 == 0) ni->proto->temp2 = 1;
660 				}
661 			}
662 		}
663 	}
664 	np->temp2 = 0;
665 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
666 		for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
667 	{
668 		if (onp->temp2 == 0) continue;
669 		pf = proj_findcell(onp);
670 		if (pf == NOPROJECTCELL) continue;
671 		if (namesame(pf->owner, proj_username) == 0)
672 		{
673 			onp->temp1 = 1;
674 			total++;
675 		}
676 	}
677 
678 	/* advise of additional cells that must be checked-in */
679 	if (total > 0)
680 	{
681 		total = 0;
682 		infstr = initinfstr();
683 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
684 			for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
685 		{
686 			if (onp == np || onp->temp1 == 0) continue;
687 			if (total > 0) addstringtoinfstr(infstr, x_(", "));
688 			addstringtoinfstr(infstr, describenodeproto(onp));
689 			total++;
690 		}
691 		ttyputmsg(_("Also checking in related cell(s): %s"), returninfstr(infstr));
692 	}
693 
694 	/* check it in */
695 	proj_checkinmany(np->lib);
696 }
697 
proj_checkout(CHAR * cellname,BOOLEAN showcell)698 void proj_checkout(CHAR *cellname, BOOLEAN showcell)
699 {
700 	REGISTER NODEPROTO *np, *newvers, *oldvers;
701 	REGISTER NODEINST *ni;
702 	REGISTER BOOLEAN worked, propagated;
703 	REGISTER INTBIG total;
704 	REGISTER LIBRARY *lib, *olib;
705 	CHAR projectpath[256], projectfile[256], *argv[3];
706 	PROJECTCELL *pf;
707 
708 	/* find out which cell is being checked out */
709 	oldvers = getnodeproto(cellname);
710 	if (oldvers == NONODEPROTO)
711 	{
712 		ttyputerr(_("Cannot identify cell '%s'"), cellname);
713 		return;
714 	}
715 	lib = oldvers->lib;
716 
717 	/* make sure there is a valid user name */
718 	if (proj_getusername(FALSE, lib))
719 	{
720 		ttyputerr(_("No valid user"));
721 		return;
722 	}
723 
724 	/* get location of project file */
725 	if (proj_getprojinfo(lib, projectpath, projectfile))
726 	{
727 		ttyputerr(_("Cannot find project file"));
728 		return;
729 	}
730 
731 	/* lock the project file */
732 	if (proj_lockprojfile(projectpath, projectfile))
733 	{
734 		ttyputerr(_("Couldn't lock project file"));
735 		return;
736 	}
737 
738 	/* read the project file */
739 	worked = FALSE;
740 	if (proj_readprojectfile(projectpath, projectfile))
741 		ttyputerr(_("Cannot read project file")); else
742 	{
743 		/* find this in the project file */
744 		pf = proj_findcell(oldvers);
745 		if (pf == NOPROJECTCELL) ttyputerr(_("This cell is not in the project")); else
746 		{
747 			/* see if it is available */
748 			if (*pf->owner != 0)
749 			{
750 				if (namesame(pf->owner, proj_username) == 0)
751 				{
752 					ttyputerr(_("This cell is already checked out to you"));
753 					proj_marklocked(oldvers, FALSE);
754 				} else
755 				{
756 					ttyputerr(_("This cell is already checked out to '%s'"), pf->owner);
757 				}
758 			} else
759 			{
760 				/* make sure we have the latest version */
761 				if (pf->cellversion > oldvers->version)
762 				{
763 					ttyputerr(_("Cannot check out %s because you don't have the latest version (yours is %ld, project has %ld)"),
764 						describenodeproto(oldvers), oldvers->version, pf->cellversion);
765 					ttyputmsg(_("Do an 'update' first"));
766 				} else
767 				{
768 					if (!proj_getcomments(pf, x_("out")))
769 					{
770 						if (proj_startwritingprojectfile(projectpath, projectfile))
771 							ttyputerr(_("Cannot write project file")); else
772 						{
773 							/* prevent tools (including this one) from seeing the change */
774 							(void)proj_turnofftools();
775 
776 							/* remove highlighting */
777 							us_clearhighlightcount();
778 
779 							/* make new version */
780 							newvers = copynodeproto(oldvers, lib, oldvers->protoname, TRUE);
781 
782 							/* restore tool state */
783 							proj_restoretoolstate();
784 
785 							if (newvers == NONODEPROTO)
786 								ttyputerr(_("Error making new version of cell")); else
787 							{
788 								(*el_curconstraint->solve)(newvers);
789 
790 								/* replace former usage with new version */
791 								if (proj_usenewestversion(oldvers, newvers))
792 									ttyputerr(_("Error replacing instances of new %s"),
793 										describenodeproto(oldvers)); else
794 								{
795 									/* update record for the cell */
796 									(void)reallocstring(&pf->owner, proj_username, proj_tool->cluster);
797 									(void)reallocstring(&pf->lastowner, x_(""), proj_tool->cluster);
798 									proj_marklocked(newvers, FALSE);
799 									worked = TRUE;
800 								}
801 							}
802 						}
803 						proj_endwritingprojectfile();
804 					}
805 				}
806 			}
807 		}
808 	}
809 
810 	/* relase project file lock */
811 	proj_unlockprojfile(projectpath, projectfile);
812 
813 	/* if it worked, print dependencies and display */
814 	if (worked)
815 	{
816 		ttyputmsg(_("Cell %s checked out for your use"), describenodeproto(newvers));
817 
818 		/* advise of possible problems with other checkouts higher up in the hierarchy */
819 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
820 			for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
821 				np->temp1 = 0;
822 		newvers->temp1 = 1;
823 		propagated = TRUE;
824 		while (propagated)
825 		{
826 			propagated = FALSE;
827 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
828 				for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
829 			{
830 				if (np->temp1 == 1)
831 				{
832 					propagated = TRUE;
833 					np->temp1 = 2;
834 					for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
835 						if (ni->parent->temp1 == 0) ni->parent->temp1 = 1;
836 				}
837 			}
838 		}
839 		newvers->temp1 = 0;
840 		total = 0;
841 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
842 			for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
843 		{
844 			if (np->temp1 == 0) continue;
845 			pf = proj_findcell(np);
846 			if (pf == NOPROJECTCELL) continue;
847 			if (*pf->owner != 0 && namesame(pf->owner, proj_username) != 0)
848 			{
849 				np->temp1 = 3;
850 				np->temp2 = (INTBIG)pf;
851 				total++;
852 			}
853 		}
854 		if (total != 0)
855 		{
856 			ttyputmsg(_("*** Warning: the following cells are above this in the hierarchy"));
857 			ttyputmsg(_("*** and are checked out to others.  This may cause problems"));
858 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
859 				for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
860 			{
861 				if (np->temp1 != 3) continue;
862 				pf = (PROJECTCELL *)np->temp2;
863 				ttyputmsg(_("    %s is checked out to %s"), describenodeproto(np), pf->owner);
864 			}
865 		}
866 
867 		/* advise of possible problems with other checkouts lower down in the hierarchy */
868 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
869 			for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
870 				np->temp1 = 0;
871 		newvers->temp1 = 1;
872 		propagated = TRUE;
873 		while(propagated)
874 		{
875 			propagated = FALSE;
876 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
877 				for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
878 			{
879 				if (np->temp1 == 1)
880 				{
881 					propagated = TRUE;
882 					np->temp1 = 2;
883 					for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
884 					{
885 						if (ni->proto->primindex != 0) continue;
886 						if (ni->proto->temp1 == 0) ni->proto->temp1 = 1;
887 					}
888 				}
889 			}
890 		}
891 		newvers->temp1 = 0;
892 		total = 0;
893 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
894 			for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
895 		{
896 			if (np->temp1 == 0) continue;
897 			pf = proj_findcell(np);
898 			if (pf == NOPROJECTCELL) continue;
899 			if (*pf->owner != 0 && namesame(pf->owner, proj_username) != 0)
900 			{
901 				np->temp1 = 3;
902 				np->temp2 = (INTBIG)pf;
903 				total++;
904 			}
905 		}
906 		if (total != 0)
907 		{
908 			ttyputmsg(_("*** Warning: the following cells are below this in the hierarchy"));
909 			ttyputmsg(_("*** and are checked out to others.  This may cause problems"));
910 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
911 				for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
912 			{
913 				if (np->temp1 != 3) continue;
914 				pf = (PROJECTCELL *)np->temp2;
915 				ttyputmsg(_("    %s is checked out to %s"), describenodeproto(np), pf->owner);
916 			}
917 		}
918 
919 		/* display the checked-out cell */
920 		if (showcell)
921 		{
922 			argv[0] = describenodeproto(newvers);
923 			us_editcell(1, argv);
924 			us_endchanges(NOWINDOWPART);
925 		}
926 	}
927 }
928 
929 /* Project Old Version */
930 static DIALOGITEM proj_oldversdialogitems[] =
931 {
932  /*  1 */ {0, {176,224,200,288}, BUTTON, N_("OK")},
933  /*  2 */ {0, {176,16,200,80}, BUTTON, N_("Cancel")},
934  /*  3 */ {0, {4,8,20,140}, MESSAGE, N_("Old version of cell")},
935  /*  4 */ {0, {28,12,166,312}, SCROLL, x_("")},
936  /*  5 */ {0, {4,140,20,312}, MESSAGE, x_("")}
937 };
938 static DIALOG proj_oldversdialog = {{108,75,318,396}, N_("Get Old Version of Cell"), 0, 5, proj_oldversdialogitems, 0, 0};
939 
940 /* special items for the "get old version" dialog: */
941 #define DPRV_CELLLIST  4		/* Cell list (scroll) */
942 #define DPRV_CELLNAME  5		/* Cell name (stat text) */
943 
proj_getoldversion(CHAR * cellname)944 void proj_getoldversion(CHAR *cellname)
945 {
946 	PROJECTCELL *pf, statpf;
947 	REGISTER INTBIG version;
948 	REGISTER time_t date;
949 	REGISTER INTBIG itemHit, count, i, len;
950 	REGISTER LIBRARY *lib;
951 	REGISTER NODEPROTO *np;
952 	CHAR line[256], projectpath[256], projectfile[256], **filelist, sep[2], *pt;
953 	REGISTER void *dia;
954 
955 	/* find out which cell is being checked out */
956 	np = getnodeproto(cellname);
957 	if (np == NONODEPROTO)
958 	{
959 		ttyputerr(_("Cannot identify cell '%s'"), cellname);
960 		return;
961 	}
962 	lib = np->lib;
963 
964 	/* get location of project file */
965 	if (proj_getprojinfo(lib, projectpath, projectfile))
966 	{
967 		ttyputerr(_("Cannot find project file"));
968 		return;
969 	}
970 
971 	if (proj_readprojectfile(projectpath, projectfile))
972 	{
973 		ttyputerr(_("Cannot read project file"));
974 		return;
975 	}
976 
977 	pf = proj_findcell(np);
978 	if (pf == NOPROJECTCELL)
979 	{
980 		ttyputerr(_("Cell %s is not in the project"), describenodeproto(np));
981 		return;
982 	}
983 
984 	/* find all files in the directory for this cell */
985 	projectfile[estrlen(projectfile)-5] = 0;
986 	estrcat(projectpath, projectfile);
987 	estrcat(projectpath, DIRSEPSTR);
988 	estrcat(projectpath, pf->cellname);
989 	estrcat(projectpath, DIRSEPSTR);
990 	count = filesindirectory(projectpath, &filelist);
991 
992 	dia = DiaInitDialog(&proj_oldversdialog);
993 	if (dia == 0) return;
994 	DiaSetText(dia, DPRV_CELLNAME, cellname);
995 	DiaInitTextDialog(dia, DPRV_CELLLIST, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
996 		SCSELMOUSE);
997 	for(i=0; i<count; i++)
998 	{
999 		estrcpy(line, filelist[i]);
1000 		len = estrlen(line);
1001 		if (estrcmp(&line[len-5], x_(".elib")) != 0) continue;
1002 		line[len-5] = 0;
1003 		version = eatoi(line);
1004 		if (version <= 0) continue;
1005 		if (version >= pf->cellversion) continue;
1006 		for(pt = line; *pt != 0; pt++) if (*pt == '-') break;
1007 		if (*pt != '-') continue;
1008 		if (estrcmp(&pt[1], pf->cellview->viewname) != 0) continue;
1009 
1010 		/* file is good, display it */
1011 		estrcpy(projectfile, projectpath);
1012 		estrcat(projectfile, sep);
1013 		estrcat(projectfile, filelist[i]);
1014 		date = filedate(projectfile);
1015 		esnprintf(line, 256, _("Version %ld, %s"), version, timetostring(date));
1016 		DiaStuffLine(dia, DPRV_CELLLIST, line);
1017 	}
1018 	DiaSelectLine(dia, DPRV_CELLLIST, -1);
1019 	for(;;)
1020 	{
1021 		itemHit = DiaNextHit(dia);
1022 		if (itemHit == OK || itemHit == CANCEL) break;
1023 	}
1024 	version = -1;
1025 	i = DiaGetCurLine(dia, DPRV_CELLLIST);
1026 	if (i >= 0)
1027 	{
1028 		pt = DiaGetScrollLine(dia, DPRV_CELLLIST, i);
1029 		if (estrlen(pt) > 8) version = eatoi(&pt[8]);
1030 	}
1031 	DiaDoneDialog(dia);
1032 	if (itemHit == CANCEL) return;
1033 	if (version < 0) return;
1034 
1035 	/* build a fake record to describe this cell */
1036 	statpf = *pf;
1037 	statpf.cellversion = version;
1038 
1039 	np = proj_getcell(&statpf, lib);
1040 	if (np == NONODEPROTO)
1041 		ttyputerr(_("Error retrieving old version of cell"));
1042 	proj_marklocked(np, FALSE);
1043 	(*el_curconstraint->solve)(np);
1044 	ttyputmsg(_("Cell %s is now in this library"), describenodeproto(np));
1045 }
1046 
proj_update(LIBRARY * lib)1047 void proj_update(LIBRARY *lib)
1048 {
1049 	CHAR projectpath[256], projectfile[256];
1050 	PROJECTCELL *pf;
1051 	REGISTER INTBIG total;
1052 	REGISTER NODEPROTO *oldnp, *newnp;
1053 
1054 	/* make sure there is a valid user name */
1055 	if (proj_getusername(FALSE, lib))
1056 	{
1057 		ttyputerr(_("No valid user"));
1058 		return;
1059 	}
1060 
1061 	/* get location of project file */
1062 	if (proj_getprojinfo(lib, projectpath, projectfile))
1063 	{
1064 		ttyputerr(_("Cannot find project file"));
1065 		return;
1066 	}
1067 
1068 	/* lock the project file */
1069 	if (proj_lockprojfile(projectpath, projectfile))
1070 	{
1071 		ttyputerr(_("Couldn't lock project file"));
1072 		return;
1073 	}
1074 
1075 	/* read the project file */
1076 	us_clearhighlightcount();
1077 	if (proj_readprojectfile(projectpath, projectfile))
1078 		ttyputerr(_("Cannot read project file")); else
1079 	{
1080 		/* check to see which cells are changed/added */
1081 		total = 0;
1082 		for(pf = proj_firstprojectcell; pf != NOPROJECTCELL; pf = pf->nextprojectcell)
1083 		{
1084 			oldnp = db_findnodeprotoname(pf->cellname, pf->cellview, el_curlib);
1085 			if (oldnp != NONODEPROTO && oldnp->version >= pf->cellversion) continue;
1086 
1087 			/* this is a new one */
1088 			newnp = proj_getcell(pf, lib);
1089 			if (newnp == NONODEPROTO)
1090 			{
1091 				if (pf->cellview == el_unknownview)
1092 				{
1093 					ttyputerr(_("Error bringing in %s;%ld"), pf->cellname, pf->cellversion);
1094 				} else
1095 				{
1096 					ttyputerr(_("Error bringing in %s{%s};%ld"), pf->cellname, pf->cellview->sviewname,
1097 						pf->cellversion);
1098 				}
1099 			} else
1100 			{
1101 				if (oldnp != NONODEPROTO && proj_usenewestversion(oldnp, newnp))
1102 					ttyputerr(_("Error replacing instances of new %s"), describenodeproto(oldnp)); else
1103 				{
1104 					if (pf->cellview == el_unknownview)
1105 					{
1106 						ttyputmsg(_("Brought in cell %s;%ld"), pf->cellname, pf->cellversion);
1107 					} else
1108 					{
1109 						ttyputmsg(_("Brought in cell %s{%s};%ld"), pf->cellname, pf->cellview->sviewname,
1110 							pf->cellversion);
1111 					}
1112 					total++;
1113 				}
1114 			}
1115 		}
1116 	}
1117 
1118 	/* relase project file lock */
1119 	proj_unlockprojfile(projectpath, projectfile);
1120 
1121 	/* make sure all cell locks are correct */
1122 	proj_validatelocks(lib);
1123 
1124 	/* summarize */
1125 	if (total == 0) ttyputmsg(_("Project is up-to-date")); else
1126 		ttyputmsg(_("Updated %ld %s"), total, makeplural(_("cell"), total));
1127 }
1128 
proj_buildproject(LIBRARY * lib)1129 void proj_buildproject(LIBRARY *lib)
1130 {
1131 	CHAR libraryname[256], librarypath[256], newname[256], projfile[256], *pars[2];
1132 	REGISTER INTBIG i, extpos;
1133 	REGISTER NODEPROTO *np;
1134 	FILE *io;
1135 
1136 	/* verify that a project is to be built */
1137 	us_noyesdlog(_("Are you sure you want to create a multi-user project from this library?"), pars);
1138 	if (namesame(pars[0], x_("yes")) != 0) return;
1139 
1140 	/* get path prefix for cell libraries */
1141 	estrcpy(librarypath, lib->libfile);
1142 	extpos = -1;
1143 	for(i = estrlen(librarypath)-1; i > 0; i--)
1144 	{
1145 		if (librarypath[i] == DIRSEP) break;
1146 		if (librarypath[i] == '.')
1147 		{
1148 			if (extpos < 0) extpos = i;
1149 		}
1150 	}
1151 	if (extpos < 0) estrcat(librarypath, x_("ELIB")); else
1152 		estrcpy(&librarypath[extpos], x_("ELIB"));
1153 	if (librarypath[i] == DIRSEP)
1154 	{
1155 		estrcpy(libraryname, &librarypath[i+1]);
1156 		librarypath[i] = 0;
1157 	} else
1158 	{
1159 		estrcpy(libraryname, librarypath);
1160 		librarypath[0] = 0;
1161 	}
1162 
1163 	/* create the top-level directory for this library */
1164 	estrcpy(newname, librarypath);
1165 	estrcat(newname, DIRSEPSTR);
1166 	estrcat(newname, libraryname);
1167 	if (fileexistence(newname) != 0)
1168 	{
1169 		ttyputerr(_("Project directory '%s' already exists"), newname);
1170 		return;
1171 	}
1172 	if (createdirectory(newname))
1173 	{
1174 		ttyputerr(_("Could not create project directory '%s'"), newname);
1175 		return;
1176 	}
1177 	ttyputmsg(_("Making project directory '%s'..."), newname);
1178 
1179 	/* create the project file */
1180 	estrcpy(projfile, librarypath);
1181 	estrcat(projfile, DIRSEPSTR);
1182 	estrcat(projfile, libraryname);
1183 	estrcat(projfile, x_(".proj"));
1184 	io = xcreate(projfile, proj_filetypeproj, 0, 0);
1185 	if (io == NULL)
1186 	{
1187 		ttyputerr(_("Could not create project file '%s'"), projfile);
1188 		return;
1189 	}
1190 
1191 	/* turn off all tools */
1192 	if (proj_turnofftools())
1193 	{
1194 		ttyputerr(_("Could not save tool state"));
1195 		return;
1196 	}
1197 
1198 	/* make libraries for every cell */
1199 	setvalkey((INTBIG)lib, VLIBRARY, proj_pathkey, (INTBIG)projfile, VSTRING);
1200 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1201 	{
1202 		/* ignore old unused cell versions */
1203 		if (np->newestversion != np)
1204 		{
1205 			if (np->firstinst == NONODEINST) continue;
1206 			ttyputmsg(_("Warning: including old version of cell %s"), describenodeproto(np));
1207 		}
1208 
1209 		/* write the cell to disk in its own library */
1210 		ttyputmsg(_("Entering cell %s"), describenodeproto(np));
1211 		if (proj_writecell(np)) break;
1212 
1213 		/* make an entry in the project file */
1214 		xprintf(io, _(":%s:%s:%ld-%s.elib:::Initial checkin\n"), libraryname, np->protoname,
1215 			np->version, np->cellview->viewname);
1216 
1217 		/* mark this cell "checked in" and locked */
1218 		proj_marklocked(np, TRUE);
1219 	}
1220 
1221 	/* restore tool state */
1222 	proj_restoretoolstate();
1223 
1224 	/* close project file */
1225 	xclose(io);
1226 
1227 	/* make sure library variables are proper */
1228 	if (getvalkey((INTBIG)lib, VLIBRARY, VSTRING, proj_userkey) != NOVARIABLE)
1229 		(void)delvalkey((INTBIG)lib, VLIBRARY, proj_userkey);
1230 
1231 	/* advise the user of this library */
1232 	ttyputmsg(_("The current library should be saved and used by new users"));
1233 }
1234 
proj_addcell(CHAR * cellname)1235 void proj_addcell(CHAR *cellname)
1236 {
1237 	REGISTER NODEPROTO *np;
1238 	REGISTER LIBRARY *lib;
1239 	CHAR projectpath[256], projectfile[256], libname[256];
1240 	PROJECTCELL *pf, *lastpf;
1241 
1242 	/* find out which cell is being added */
1243 	np = getnodeproto(cellname);
1244 	if (np == NONODEPROTO)
1245 	{
1246 		ttyputerr(_("Cannot identify cell '%s'"), cellname);
1247 		return;
1248 	}
1249 	lib = np->lib;
1250 	if (np->newestversion != np)
1251 	{
1252 		ttyputerr(_("Cannot add an old version of the cell"));
1253 		return;
1254 	}
1255 
1256 	/* make sure there is a valid user name */
1257 	if (proj_getusername(FALSE, lib))
1258 	{
1259 		ttyputerr(_("No valid user"));
1260 		return;
1261 	}
1262 
1263 	/* get location of project file */
1264 	if (proj_getprojinfo(lib, projectpath, projectfile))
1265 	{
1266 		ttyputerr(_("Cannot find project file"));
1267 		return;
1268 	}
1269 
1270 	/* lock the project file */
1271 	if (proj_lockprojfile(projectpath, projectfile))
1272 	{
1273 		ttyputerr(_("Couldn't lock project file"));
1274 		return;
1275 	}
1276 
1277 	/* read the project file */
1278 	if (proj_readprojectfile(projectpath, projectfile))
1279 		ttyputerr(_("Cannot read project file")); else
1280 	{
1281 		/* find this in the project file */
1282 		lastpf = NOPROJECTCELL;
1283 		for(pf = proj_firstprojectcell; pf != NOPROJECTCELL; pf = pf->nextprojectcell)
1284 		{
1285 			if (estrcmp(pf->cellname, np->protoname) == 0 &&
1286 				pf->cellview == np->cellview) break;
1287 			lastpf = pf;
1288 		}
1289 		if (pf != NOPROJECTCELL) ttyputerr(_("This cell is already in the project")); else
1290 		{
1291 			if (proj_startwritingprojectfile(projectpath, projectfile))
1292 				ttyputerr(_("Cannot write project file")); else
1293 			{
1294 				if (proj_writecell(np))
1295 					ttyputerr(_("Error writing cell file")); else
1296 				{
1297 					/* create new entry for this cell */
1298 					pf = proj_allocprojectcell();
1299 					if (pf == 0)
1300 						ttyputerr(_("Cannot add project record")); else
1301 					{
1302 						estrcpy(libname, projectfile);
1303 						libname[estrlen(libname)-5] = 0;
1304 						(void)allocstring(&pf->libname, libname, proj_tool->cluster);
1305 						(void)allocstring(&pf->cellname, np->protoname, proj_tool->cluster);
1306 						pf->cellview = np->cellview;
1307 						pf->cellversion = np->version;
1308 						(void)allocstring(&pf->owner, x_(""), proj_tool->cluster);
1309 						(void)allocstring(&pf->lastowner, proj_username, proj_tool->cluster);
1310 						(void)allocstring(&pf->comment, _("Initial checkin"), proj_tool->cluster);
1311 
1312 						/* link it in */
1313 						pf->nextprojectcell = NOPROJECTCELL;
1314 						if (lastpf == NOPROJECTCELL) proj_firstprojectcell = pf; else
1315 							lastpf->nextprojectcell = pf;
1316 
1317 						/* mark this cell "checked in" and locked */
1318 						proj_marklocked(np, TRUE);
1319 
1320 						ttyputmsg(_("Cell %s added to the project"), describenodeproto(np));
1321 					}
1322 				}
1323 
1324 				/* save new project file */
1325 				proj_endwritingprojectfile();
1326 			}
1327 		}
1328 	}
1329 
1330 	/* relase project file lock */
1331 	proj_unlockprojfile(projectpath, projectfile);
1332 }
1333 
proj_deletecell(CHAR * cellname)1334 void proj_deletecell(CHAR *cellname)
1335 {
1336 	REGISTER NODEPROTO *np, *onp;
1337 	REGISTER NODEINST *ni;
1338 	REGISTER LIBRARY *lib, *olib;
1339 	CHAR projectpath[256], projectfile[256], *pt;
1340 	PROJECTCELL *pf, *lastpf;
1341 	REGISTER void *infstr;
1342 
1343 	/* find out which cell is being deleted */
1344 	np = getnodeproto(cellname);
1345 	if (np == NONODEPROTO)
1346 	{
1347 		ttyputerr(_("Cannot identify cell '%s'"), cellname);
1348 		return;
1349 	}
1350 	lib = np->lib;
1351 
1352 	/* make sure the cell is not being used */
1353 	if (np->firstinst != NONODEINST)
1354 	{
1355 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
1356 			for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
1357 				onp->temp1 = 0;
1358 		for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
1359 			ni->parent->temp1++;
1360 		ttyputerr(_("Cannot delete cell %s because it is still being used by:"), cellname);
1361 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
1362 			for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
1363 				if (onp->temp1 != 0)
1364 					ttyputmsg(_("   Cell %s has %ld instance(s)"), describenodeproto(onp), onp->temp1);
1365 		return;
1366 	}
1367 
1368 	/* make sure there is a valid user name */
1369 	if (proj_getusername(FALSE, lib))
1370 	{
1371 		ttyputerr(_("No valid user"));
1372 		return;
1373 	}
1374 
1375 	/* get location of project file */
1376 	if (proj_getprojinfo(lib, projectpath, projectfile))
1377 	{
1378 		ttyputerr(_("Cannot find project file"));
1379 		return;
1380 	}
1381 
1382 	/* lock the project file */
1383 	if (proj_lockprojfile(projectpath, projectfile))
1384 	{
1385 		ttyputerr(_("Couldn't lock project file"));
1386 		return;
1387 	}
1388 
1389 	/* read the project file */
1390 	if (proj_readprojectfile(projectpath, projectfile))
1391 		ttyputerr(_("Cannot read project file")); else
1392 	{
1393 		/* make sure the user has no cells checked-out */
1394 		for(pf = proj_firstprojectcell; pf != NOPROJECTCELL; pf = pf->nextprojectcell)
1395 			if (namesame(pf->owner, proj_username) == 0) break;
1396 		if (pf != NOPROJECTCELL)
1397 		{
1398 			ttyputerr(_("Before deleting a cell from the project, you must check-in all of your work."));
1399 			ttyputerr(_("This is because the deletion may be dependent upon changes recently made."));
1400 			infstr = initinfstr();
1401 			for(pf = proj_firstprojectcell; pf != NOPROJECTCELL; pf = pf->nextprojectcell)
1402 			{
1403 				if (namesame(pf->owner, proj_username) != 0) continue;
1404 				addstringtoinfstr(infstr, pf->cellname);
1405 				if (pf->cellview != el_unknownview)
1406 				{
1407 					addstringtoinfstr(infstr, x_("{"));
1408 					addstringtoinfstr(infstr, pf->cellview->sviewname);
1409 					addstringtoinfstr(infstr, x_("}"));
1410 				}
1411 				addstringtoinfstr(infstr, x_(", "));
1412 			}
1413 			pt = returninfstr(infstr);
1414 			pt[estrlen(pt)-2] = 0;
1415 			ttyputerr(_("These cells are checked out to you: %s"), pt);
1416 		} else
1417 		{
1418 			/* find this in the project file */
1419 			lastpf = NOPROJECTCELL;
1420 			for(pf = proj_firstprojectcell; pf != NOPROJECTCELL; pf = pf->nextprojectcell)
1421 			{
1422 				if (estrcmp(pf->cellname, np->protoname) == 0 &&
1423 					pf->cellview == np->cellview) break;
1424 				lastpf = pf;
1425 			}
1426 			if (pf == NOPROJECTCELL) ttyputerr(_("This cell is not in the project")); else
1427 			{
1428 				if (proj_startwritingprojectfile(projectpath, projectfile))
1429 					ttyputerr(_("Cannot write project file")); else
1430 				{
1431 					/* unlink it */
1432 					if (lastpf == NOPROJECTCELL)
1433 						proj_firstprojectcell = pf->nextprojectcell; else
1434 							lastpf->nextprojectcell = pf->nextprojectcell;
1435 
1436 					/* delete the entry */
1437 					efree(pf->libname);
1438 					efree(pf->cellname);
1439 					efree(pf->owner);
1440 					efree(pf->lastowner);
1441 					efree(pf->comment);
1442 					proj_freeprojectcell(pf);
1443 
1444 					/* mark this cell unlocked */
1445 					proj_marklocked(np, FALSE);
1446 
1447 					/* save new project file */
1448 					proj_endwritingprojectfile();
1449 
1450 					ttyputmsg(_("Cell %s deleted from the project"), describenodeproto(np));
1451 				}
1452 			}
1453 		}
1454 	}
1455 
1456 	/* relase project file lock */
1457 	proj_unlockprojfile(projectpath, projectfile);
1458 }
1459 
1460 /************************ USER DATABASE ***********************/
1461 
1462 /* Project User */
1463 static DIALOGITEM proj_usersdialogitems[] =
1464 {
1465  /*  1 */ {0, {28,184,52,312}, BUTTON, N_("Select User")},
1466  /*  2 */ {0, {188,212,212,276}, BUTTON, N_("Cancel")},
1467  /*  3 */ {0, {28,4,220,172}, SCROLL, x_("")},
1468  /*  4 */ {0, {8,60,24,112}, MESSAGE, N_("Users:")},
1469  /*  5 */ {0, {136,184,160,312}, BUTTON, N_("Delete User")},
1470  /*  6 */ {0, {64,184,88,312}, BUTTON, N_("Change Password")},
1471  /*  7 */ {0, {100,184,124,312}, BUTTON, N_("New User")}
1472 };
1473 static DIALOG proj_usersdialog = {{50,75,279,398}, N_("User Name"), 0, 7, proj_usersdialogitems, 0, 0};
1474 
1475 /* special items for the "User selection" dialog: */
1476 #define DPRU_USERLIST  3		/* User list (scroll) */
1477 #define DPRU_DELUSER   5		/* Delete user (button) */
1478 #define DPRU_CHPASS    6		/* Change password (button) */
1479 #define DPRU_NEWUSER   7		/* New user (button) */
1480 
1481 /*
1482  * Routine to obtain the user's name.  If "newone" is true, force input of a name,
1483  * otherwise, only ask if unknown.  Returns true if user name is invalid.
1484  */
proj_getusername(BOOLEAN newone,LIBRARY * lib)1485 BOOLEAN proj_getusername(BOOLEAN newone, LIBRARY *lib)
1486 {
1487 	REGISTER CHAR *pt, *pwd;
1488 	REGISTER INTBIG itemHit, writeback, i;
1489 	REGISTER PUSER *pu, *lastpu;
1490 	REGISTER VARIABLE *var;
1491 	CHAR *truename, userline[256], pwdline[256], projectpath[256], projectfile[256];
1492 	FILE *io;
1493 	REGISTER void *infstr, *dia;
1494 
1495 	/* if name exists and not forcing a new user name, stop now */
1496 	if (!newone && proj_username[0] != 0) return(FALSE);
1497 
1498 	/* read user database */
1499 	proj_users = NOPUSER;
1500 	infstr = initinfstr();
1501 	addstringtoinfstr(infstr, el_libdir);
1502 	addstringtoinfstr(infstr, PUSERFILE);
1503 	io = xopen(returninfstr(infstr), proj_filetypeprojusers, x_(""), &truename);
1504 	if (io == NULL) ttyputmsg(_("Creating new user database")); else
1505 	{
1506 		/* read the users file */
1507 		lastpu = NOPUSER;
1508 		for(;;)
1509 		{
1510 			if (xfgets(userline, 256, io)) break;
1511 			for(pt = userline; *pt != 0; pt++) if (*pt == ':') break;
1512 			if (*pt != ':')
1513 			{
1514 				ttyputerr(_("Missing ':' in user file: %s"), userline);
1515 				break;
1516 			}
1517 			*pt++ = 0;
1518 			pu = (PUSER *)emalloc(sizeof (PUSER), proj_tool->cluster);
1519 			if (pu == 0) break;
1520 			(void)allocstring(&pu->username, userline, proj_tool->cluster);
1521 			(void)allocstring(&pu->userpassword, pt, proj_tool->cluster);
1522 			pu->nextpuser = NOPUSER;
1523 			if (proj_users == NOPUSER) proj_users = lastpu = pu; else
1524 				lastpu->nextpuser = pu;
1525 			lastpu = pu;
1526 		}
1527 		xclose(io);
1528 	}
1529 
1530 	/* if not forcing a new user name, see if it is on the library */
1531 	if (!newone)
1532 	{
1533 		/* if already on the library, get it */
1534 		var = getvalkey((INTBIG)lib, VLIBRARY, VSTRING, proj_userkey);
1535 		if (var != NOVARIABLE)
1536 		{
1537 			estrcpy(proj_username, (CHAR *)var->addr);
1538 			for(pu = proj_users; pu != NOPUSER; pu = pu->nextpuser)
1539 				if (estrcmp(proj_username, pu->username) == 0) break;
1540 			if (pu != NOPUSER)
1541 			{
1542 				pwd = proj_wantpassword(1, proj_username);
1543 				if (estrcmp(pwd, pu->userpassword) == 0) return(FALSE);
1544 				ttyputmsg(_("Incorrect password"));
1545 				proj_username[0] = 0;
1546 				return(TRUE);
1547 			}
1548 			proj_username[0] = 0;
1549 			(void)delvalkey((INTBIG)lib, VLIBRARY, proj_userkey);
1550 		}
1551 	}
1552 
1553 
1554 	/* show the users dialog */
1555 	writeback = 0;
1556 	dia = DiaInitDialog(&proj_usersdialog);
1557 	if (dia == 0) return(TRUE);
1558 	DiaInitTextDialog(dia, DPRU_USERLIST, proj_initusers, proj_nextuser, DiaNullDlogDone, 0,
1559 		SCSELMOUSE | SCSELKEY | SCDOUBLEQUIT);
1560 	for(;;)
1561 	{
1562 		itemHit = DiaNextHit(dia);
1563 		if (itemHit == CANCEL) break;
1564 		if (itemHit == OK)
1565 		{
1566 			/* validate the user name */
1567 			i = DiaGetCurLine(dia, DPRU_USERLIST);
1568 			if (i < 0) continue;
1569 			pt = DiaGetScrollLine(dia, DPRU_USERLIST, i);
1570 			for(pu = proj_users; pu != NOPUSER; pu = pu->nextpuser)
1571 				if (estrcmp(pt, pu->username) == 0) break;
1572 			if (pu == NOPUSER) continue;
1573 			pwd = proj_wantpassword(1, pt);
1574 			if (estrcmp(pwd, pu->userpassword) == 0)
1575 			{
1576 				estrcpy(proj_username, pu->username);
1577 				(void)setvalkey((INTBIG)lib, VLIBRARY, proj_userkey,
1578 					(INTBIG)proj_username, VSTRING);
1579 				break;
1580 			}
1581 			ttyputmsg(_("Incorrect password"));
1582 			continue;
1583 		}
1584 		if (itemHit == DPRU_DELUSER)
1585 		{
1586 			/* delete user */
1587 			i = DiaGetCurLine(dia, DPRU_USERLIST);
1588 			if (i < 0) continue;
1589 			pt = DiaGetScrollLine(dia, DPRU_USERLIST, i);
1590 			lastpu = NOPUSER;
1591 			for(pu = proj_users; pu != NOPUSER; pu = pu->nextpuser)
1592 			{
1593 				if (estrcmp(pt, pu->username) == 0) break;
1594 				lastpu = pu;
1595 			}
1596 			if (pu == NOPUSER) continue;
1597 			pwd = proj_wantpassword(1, pt);
1598 			if (estrcmp(pwd, pu->userpassword) != 0)
1599 			{
1600 				ttyputerr(_("Incorrect password"));
1601 				continue;
1602 			}
1603 			if (lastpu == NOPUSER) proj_users = pu->nextpuser; else
1604 				lastpu->nextpuser = pu->nextpuser;
1605 			efree(pu->username);
1606 			efree(pu->userpassword);
1607 			efree((CHAR *)pu);
1608 			DiaLoadTextDialog(dia, DPRU_USERLIST, proj_initusers, proj_nextuser,
1609 				DiaNullDlogDone, 0);
1610 			writeback = 1;
1611 			continue;
1612 		}
1613 		if (itemHit == DPRU_CHPASS)
1614 		{
1615 			/* change password */
1616 			i = DiaGetCurLine(dia, DPRU_USERLIST);
1617 			if (i < 0) continue;
1618 			pt = DiaGetScrollLine(dia, DPRU_USERLIST, i);
1619 			for(pu = proj_users; pu != NOPUSER; pu = pu->nextpuser)
1620 				if (estrcmp(pt, pu->username) == 0) break;
1621 			if (pu == NOPUSER) continue;
1622 			pwd = proj_wantpassword(1, pt);
1623 			if (estrcmp(pwd, pu->userpassword) != 0)
1624 			{
1625 				ttyputerr(_("Incorrect password"));
1626 				continue;
1627 			}
1628 			pwd = proj_wantpassword(2, pt);
1629 			estrcpy(pwdline, pwd);
1630 			pwd = proj_wantpassword(3, pt);
1631 			if (estrcmp(pwdline, pwd) != 0)
1632 			{
1633 				ttyputerr(_("Failed to type password the same way twice"));
1634 				continue;
1635 			}
1636 			(void)reallocstring(&pu->userpassword, pwdline, proj_tool->cluster);
1637 			writeback = 1;
1638 			continue;
1639 		}
1640 		if (itemHit == DPRU_NEWUSER)
1641 		{
1642 			/* new user */
1643 			pt = proj_wantpassword(0, x_(""));
1644 			estrcpy(userline, pt);
1645 			pwd = proj_wantpassword(1, userline);
1646 			estrcpy(pwdline, pwd);
1647 			pwd = proj_wantpassword(3, userline);
1648 			if (estrcmp(pwdline, pwd) != 0)
1649 			{
1650 				ttyputerr(_("Failed to type password the same way twice"));
1651 				continue;
1652 			}
1653 
1654 			pu = (PUSER *)emalloc(sizeof (PUSER), proj_tool->cluster);
1655 			if (pu == 0) continue;
1656 			(void)allocstring(&pu->username, userline, proj_tool->cluster);
1657 			(void)allocstring(&pu->userpassword, pwdline, proj_tool->cluster);
1658 			pu->nextpuser = proj_users;
1659 			proj_users = pu;
1660 			DiaLoadTextDialog(dia, DPRU_USERLIST, proj_initusers, proj_nextuser,
1661 				DiaNullDlogDone, 0);
1662 			writeback = 1;
1663 			continue;
1664 		}
1665 	}
1666 	DiaDoneDialog(dia);
1667 
1668 	if (itemHit == CANCEL) return(TRUE);
1669 
1670 	/* write the file back if necessary */
1671 	if (writeback != 0)
1672 	{
1673 		infstr = initinfstr();
1674 		addstringtoinfstr(infstr, el_libdir);
1675 		addstringtoinfstr(infstr, PUSERFILE);
1676 		io = xopen(returninfstr(infstr), proj_filetypeprojusers | FILETYPEWRITE, x_(""), &truename);
1677 		if (io == NULL)
1678 		{
1679 			ttyputmsg(_("Cannot save users database"));
1680 			return(TRUE);
1681 		}
1682 
1683 		/* write the users file */
1684 		for(pu = proj_users; pu != NOPUSER; pu = pu->nextpuser)
1685 			xprintf(io, x_("%s:%s\n"), pu->username, pu->userpassword);
1686 		xclose(io);
1687 
1688 		/* if switching users, update all locks in the library */
1689 		if (proj_getprojinfo(lib, projectpath, projectfile))
1690 		{
1691 			ttyputerr(_("Cannot find project file"));
1692 			return(FALSE);
1693 		}
1694 		if (proj_readprojectfile(projectpath, projectfile))
1695 		{
1696 			ttyputerr(_("Cannot read project file"));
1697 			return(FALSE);
1698 		}
1699 		proj_validatelocks(lib);
1700 	}
1701 	return(FALSE);
1702 }
1703 
1704 /* Project Password */
1705 static DIALOGITEM proj_passworddialogitems[] =
1706 {
1707  /*  1 */ {0, {72,12,96,76}, BUTTON, N_("OK")},
1708  /*  2 */ {0, {72,132,96,196}, BUTTON, N_("Cancel")},
1709  /*  3 */ {0, {12,8,28,205}, MESSAGE, N_("Password for")},
1710  /*  4 */ {0, {40,48,56,165}, EDITTEXT, x_("")}
1711 };
1712 static DIALOG proj_passworddialog = {{298,75,404,292}, N_("User / Password"), 0, 4, proj_passworddialogitems, 0, 0};
1713 
1714 /* special items for the "Password prompt" dialog: */
1715 #define DPRP_USERNAME  3		/* User name (stat text) */
1716 #define DPRP_PASSWORD  4		/* Password (edit text) */
1717 
1718 /*
1719  * Routine to prompt for a user name/password, according to the "mode" and return
1720  * the string.  "mode" is:
1721  *   0 to prompt for a user name
1722  *   1 to prompt for an existing password
1723  *   2 to prompt for a new password
1724  *   3 to prompt for a password verification
1725  */
proj_wantpassword(INTBIG mode,CHAR * username)1726 CHAR *proj_wantpassword(INTBIG mode, CHAR *username)
1727 {
1728 	REGISTER INTBIG itemHit;
1729 	static CHAR typedstuff[256];
1730 	REGISTER void *dia;
1731 
1732 	dia = DiaInitDialog(&proj_passworddialog);
1733 	if (dia == 0) return(x_(""));
1734 	switch (mode)
1735 	{
1736 		case 0:
1737 			DiaSetText(dia, DPRP_USERNAME, _("New User Name"));
1738 			break;
1739 		case 1:
1740 			esnprintf(typedstuff, 256, _("Password for %s"), username);
1741 			DiaSetText(dia, DPRP_USERNAME, typedstuff);
1742 			break;
1743 		case 2:
1744 			esnprintf(typedstuff, 256, _("New Password for %s"), username);
1745 			DiaSetText(dia, DPRP_USERNAME, typedstuff);
1746 			break;
1747 		case 3:
1748 			esnprintf(typedstuff, 256, _("Verify Password for %s"), username);
1749 			DiaSetText(dia, DPRP_USERNAME, typedstuff);
1750 			break;
1751 	}
1752 	if (mode != 0) DiaOpaqueEdit(dia, DPRP_PASSWORD);
1753 	for(;;)
1754 	{
1755 		itemHit = DiaNextHit(dia);
1756 		if (itemHit == CANCEL || itemHit == OK) break;
1757 	}
1758 	estrcpy(typedstuff, DiaGetText(dia, DPRP_PASSWORD));
1759 	DiaDoneDialog(dia);
1760 	if (mode != 0)
1761 		myencrypt(typedstuff, x_("BicIsSchediwy"));
1762 	return(typedstuff);
1763 }
1764 
proj_initusers(CHAR ** c)1765 BOOLEAN proj_initusers(CHAR **c)
1766 {
1767 	proj_userpos = proj_users;
1768 	return(TRUE);
1769 }
1770 
proj_nextuser(void)1771 CHAR *proj_nextuser(void)
1772 {
1773 	REGISTER CHAR *ret;
1774 
1775 	if (proj_userpos == NOPUSER) return(0);
1776 	ret = proj_userpos->username;
1777 	proj_userpos = proj_userpos->nextpuser;
1778 	return(ret);
1779 }
1780 
1781 /************************ PROJECT DATABASE ***********************/
1782 
proj_checkinmany(LIBRARY * lib)1783 void proj_checkinmany(LIBRARY *lib)
1784 {
1785 	REGISTER NODEPROTO *np;
1786 	CHAR projectpath[256], projectfile[256];
1787 	PROJECTCELL *pf;
1788 	REGISTER LIBRARY *olib;
1789 
1790 	/* make sure there is a valid user name */
1791 	if (proj_getusername(FALSE, lib))
1792 	{
1793 		ttyputerr(_("No valid user"));
1794 		return;
1795 	}
1796 
1797 	/* get location of project file */
1798 	if (proj_getprojinfo(lib, projectpath, projectfile))
1799 	{
1800 		ttyputerr(_("Cannot find project file"));
1801 		return;
1802 	}
1803 
1804 	/* lock the project file */
1805 	if (proj_lockprojfile(projectpath, projectfile))
1806 	{
1807 		ttyputerr(_("Couldn't lock project file"));
1808 		return;
1809 	}
1810 
1811 	/* read the project file */
1812 	if (proj_readprojectfile(projectpath, projectfile))
1813 		ttyputerr(_("Cannot read project file")); else
1814 	{
1815 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
1816 			for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1817 		{
1818 			if (np->temp1 == 0) continue;
1819 			if (stopping(STOPREASONCHECKIN)) break;
1820 
1821 			/* find this in the project file */
1822 			pf = proj_findcell(np);
1823 			if (pf == NOPROJECTCELL)
1824 				ttyputerr(_("Cell %s is not in the project"), describenodeproto(np)); else
1825 			{
1826 				/* see if it is available */
1827 				if (estrcmp(pf->owner, proj_username) != 0)
1828 					ttyputerr(_("Cell %s is not checked out to you"), describenodeproto(np)); else
1829 				{
1830 					if (!proj_getcomments(pf, x_("in")))
1831 					{
1832 						/* prepare to write it back */
1833 						if (proj_startwritingprojectfile(projectpath, projectfile))
1834 							ttyputerr(_("Cannot write project file")); else
1835 						{
1836 							/* write the cell out there */
1837 							if (proj_writecell(np))
1838 								ttyputerr(_("Error writing cell %s"), describenodeproto(np)); else
1839 							{
1840 								(void)reallocstring(&pf->owner, x_(""), proj_tool->cluster);
1841 								(void)reallocstring(&pf->lastowner, proj_username, proj_tool->cluster);
1842 								pf->cellversion = np->version;
1843 								proj_marklocked(np, TRUE);
1844 								ttyputmsg(_("Cell %s checked in"), describenodeproto(np));
1845 							}
1846 							proj_endwritingprojectfile();
1847 						}
1848 					}
1849 				}
1850 			}
1851 		}
1852 	}
1853 
1854 	/* relase project file lock */
1855 	proj_unlockprojfile(projectpath, projectfile);
1856 }
1857 
1858 /*
1859  * Routine to obtain information about the project associated with library "lib".
1860  * The path to the project is placed in "path" and the name of the project file
1861  * in that directory is placed in "projfile".  Returns true on error.
1862  */
proj_getprojinfo(LIBRARY * lib,CHAR * path,CHAR * projfile)1863 BOOLEAN proj_getprojinfo(LIBRARY *lib, CHAR *path, CHAR *projfile)
1864 {
1865 	REGISTER VARIABLE *var;
1866 	CHAR *params[2], *truename;
1867 	FILE *io;
1868 	REGISTER INTBIG i;
1869 	extern COMCOMP us_colorreadp;
1870 	REGISTER void *infstr;
1871 
1872 	/* see if there is a variable in the current library with the project path */
1873 	var = getvalkey((INTBIG)lib, VLIBRARY, VSTRING, proj_pathkey);
1874 	if (var != NOVARIABLE)
1875 	{
1876 		estrcpy(path, (CHAR *)var->addr);
1877 		io = xopen(path, proj_filetypeproj, x_(""), &truename);
1878 		if (io != 0) xclose(io); else
1879 			var = NOVARIABLE;
1880 	}
1881 	if (var == NOVARIABLE)
1882 	{
1883 		infstr = initinfstr();
1884 		addstringtoinfstr(infstr, x_("proj/"));
1885 		addstringtoinfstr(infstr, _("Project File"));
1886 		i = ttygetparam(returninfstr(infstr), &us_colorreadp, 1, params);
1887 		if (i == 0) return(TRUE);
1888 		estrcpy(path, params[0]);
1889 		setvalkey((INTBIG)lib, VLIBRARY, proj_pathkey, (INTBIG)path, VSTRING);
1890 	}
1891 
1892 	for(i = estrlen(path)-1; i>0; i--) if (path[i] == DIRSEP) break;
1893 	if (path[i] == DIRSEP)
1894 	{
1895 		estrcpy(projfile, &path[i+1]);
1896 		path[i+1] = 0;
1897 	} else
1898 	{
1899 		estrcpy(projfile, path);
1900 		path[0] = 0;
1901 	}
1902 	return(FALSE);
1903 }
1904 
1905 /* Project List */
1906 static DIALOGITEM proj_listdialogitems[] =
1907 {
1908  /*  1 */ {0, {204,312,228,376}, BUTTON, N_("Done")},
1909  /*  2 */ {0, {4,4,196,376}, SCROLL, x_("")},
1910  /*  3 */ {0, {260,4,324,376}, MESSAGE, x_("")},
1911  /*  4 */ {0, {240,4,256,86}, MESSAGE, N_("Comments:")},
1912  /*  5 */ {0, {204,120,228,220}, BUTTON, N_("Check It Out")},
1913  /*  6 */ {0, {236,4,237,376}, DIVIDELINE, x_("")},
1914  /*  7 */ {0, {204,8,228,108}, BUTTON, N_("Check It In")},
1915  /*  8 */ {0, {204,232,228,296}, BUTTON, N_("Update")}
1916 };
1917 static DIALOG proj_listdialog = {{50,75,383,462}, N_("Project Management"), 0, 8, proj_listdialogitems, 0, 0};
1918 
1919 /* special items for the "Project list" dialog: */
1920 #define DPRL_PROJLIST  2		/* Project list (scroll) */
1921 #define DPRL_COMMENTS  3		/* Comments (stat text) */
1922 #define DPRL_CHECKOUT  5		/* Check out (button) */
1923 #define DPRL_CHECKIN   7		/* Check in (button) */
1924 #define DPRL_UPDATE    8		/* Update (button) */
1925 
proj_showlistdialog(LIBRARY * lib)1926 void proj_showlistdialog(LIBRARY *lib)
1927 {
1928 	REGISTER INTBIG itemHit, i, j;
1929 	REGISTER PROJECTCELL *pf;
1930 	REGISTER void *infstr, *dia;
1931 
1932 	if (proj_getusername(FALSE, lib))
1933 	{
1934 		ttyputerr(_("No valid user"));
1935 		return;
1936 	}
1937 	proj_active = TRUE;
1938 
1939 	/* show the dialog */
1940 	dia = DiaInitDialog(&proj_listdialog);
1941 	if (dia == 0) return;
1942 	DiaInitTextDialog(dia, DPRL_PROJLIST, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone,
1943 		-1, SCSELMOUSE | SCREPORT);
1944 
1945 	/* load project information into the scroll area */
1946 	if (proj_loadlist(lib, dia))
1947 	{
1948 		DiaDoneDialog(dia);
1949 		return;
1950 	}
1951 
1952 	for(;;)
1953 	{
1954 		itemHit = DiaNextHit(dia);
1955 		if (itemHit == OK) break;
1956 		if (itemHit == DPRL_UPDATE)
1957 		{
1958 			/* update project */
1959 			proj_update(lib);
1960 			(void)proj_loadlist(lib, dia);
1961 			us_endbatch();
1962 			continue;
1963 		}
1964 		if (itemHit == DPRL_CHECKOUT || itemHit == DPRL_CHECKIN ||
1965 			itemHit == DPRL_PROJLIST)
1966 		{
1967 			/* figure out which cell is selected */
1968 			i = DiaGetCurLine(dia, DPRL_PROJLIST);
1969 			if (i < 0) continue;
1970 			for(j=0, pf = proj_firstprojectcell; pf != NOPROJECTCELL; pf = pf->nextprojectcell, j++)
1971 				if (i == j) break;
1972 			if (pf == NOPROJECTCELL) continue;
1973 
1974 			if (itemHit == DPRL_CHECKOUT)
1975 			{
1976 				/* check it out */
1977 				infstr = initinfstr();
1978 				addstringtoinfstr(infstr, pf->cellname);
1979 				if (pf->cellview != el_unknownview)
1980 				{
1981 					addtoinfstr(infstr, '{');
1982 					addstringtoinfstr(infstr, pf->cellview->sviewname);
1983 					addtoinfstr(infstr, '}');
1984 				}
1985 				proj_checkout(returninfstr(infstr), FALSE);
1986 				(void)proj_loadlist(lib, dia);
1987 				us_endbatch();
1988 				continue;
1989 			}
1990 			if (itemHit == DPRL_CHECKIN)
1991 			{
1992 				/* check it in */
1993 				infstr = initinfstr();
1994 				addstringtoinfstr(infstr, pf->cellname);
1995 				if (pf->cellview != el_unknownview)
1996 				{
1997 					addtoinfstr(infstr, '{');
1998 					addstringtoinfstr(infstr, pf->cellview->sviewname);
1999 					addtoinfstr(infstr, '}');
2000 				}
2001 				proj_checkin(returninfstr(infstr));
2002 				(void)proj_loadlist(lib, dia);
2003 				continue;
2004 			}
2005 			if (itemHit == DPRL_PROJLIST)
2006 			{
2007 				if (*pf->comment != 0) DiaSetText(dia, DPRL_COMMENTS, pf->comment);
2008 				if (*pf->owner == 0) DiaUnDimItem(dia, DPRL_CHECKOUT); else
2009 					DiaDimItem(dia, DPRL_CHECKOUT);
2010 				if (estrcmp(pf->owner, proj_username) == 0) DiaUnDimItem(dia, DPRL_CHECKIN); else
2011 					DiaDimItem(dia, DPRL_CHECKIN);
2012 				continue;
2013 			}
2014 		}
2015 	}
2016 	DiaDoneDialog(dia);
2017 }
2018 
2019 /*
2020  * Routine to display the current project information in the list dialog.
2021  * Returns true on error.
2022  */
proj_loadlist(LIBRARY * lib,void * dia)2023 BOOLEAN proj_loadlist(LIBRARY *lib, void *dia)
2024 {
2025 	REGISTER BOOLEAN failed, uptodate;
2026 	REGISTER INTBIG whichline, thisline;
2027 	REGISTER PROJECTCELL *pf, *curpf;
2028 	CHAR line[256], projectpath[256], projectfile[256];
2029 	REGISTER NODEPROTO *np, *curcell;
2030 
2031 	/* get location of project file */
2032 	if (proj_getprojinfo(lib, projectpath, projectfile))
2033 	{
2034 		ttyputerr(_("Cannot find project file"));
2035 		return(TRUE);
2036 	}
2037 
2038 	/* lock the project file */
2039 	if (proj_lockprojfile(projectpath, projectfile))
2040 	{
2041 		ttyputerr(_("Couldn't lock project file"));
2042 		return(TRUE);
2043 	}
2044 
2045 	/* read the project file */
2046 	failed = FALSE;
2047 	if (proj_readprojectfile(projectpath, projectfile))
2048 	{
2049 		ttyputerr(_("Cannot read project file"));
2050 		failed = TRUE;
2051 	}
2052 
2053 	/* relase project file lock */
2054 	proj_unlockprojfile(projectpath, projectfile);
2055 	if (failed) return(TRUE);
2056 
2057 	/* find current cell */
2058 	curcell = getcurcell();
2059 
2060 	/* show what is in the project file */
2061 	DiaLoadTextDialog(dia, DPRL_PROJLIST, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
2062 	whichline = -1;
2063 	thisline = 0;
2064 	uptodate = TRUE;
2065 	for(pf = proj_firstprojectcell; pf != NOPROJECTCELL; pf = pf->nextprojectcell)
2066 	{
2067 		/* see if project is up-to-date */
2068 		np = db_findnodeprotoname(pf->cellname, pf->cellview, el_curlib);
2069 		if (np == NONODEPROTO || np->version < pf->cellversion) uptodate = FALSE;
2070 
2071 		/* remember this line if it describes the current cell */
2072 		if (curcell != NONODEPROTO && namesame(curcell->protoname, pf->cellname) == 0 &&
2073 			curcell->cellview == pf->cellview)
2074 		{
2075 			whichline = thisline;
2076 			curpf = pf;
2077 		}
2078 
2079 		/* describe this project cell */
2080 		if (pf->cellview == el_unknownview)
2081 		{
2082 			esnprintf(line, 256, x_("%s;%ld"), pf->cellname, pf->cellversion);
2083 		} else
2084 		{
2085 			esnprintf(line, 256, x_("%s{%s};%ld"), pf->cellname, pf->cellview->sviewname,
2086 				pf->cellversion);
2087 		}
2088 		if (*pf->owner == 0)
2089 		{
2090 			estrcat(line, _(" AVAILABLE"));
2091 			if (*pf->lastowner != 0)
2092 			{
2093 				estrcat(line, _(", last mod by "));
2094 				estrcat(line, pf->lastowner);
2095 			}
2096 		} else
2097 		{
2098 			if (estrcmp(pf->owner, proj_username) == 0)
2099 			{
2100 				estrcat(line, _(" EDITABLE, checked out to you"));
2101 			} else
2102 			{
2103 				estrcat(line, _(" UNAVAILABLE, checked out to "));
2104 				estrcat(line, pf->owner);
2105 			}
2106 		}
2107 		DiaStuffLine(dia, DPRL_PROJLIST, line);
2108 		thisline++;
2109 	}
2110 	DiaSelectLine(dia, DPRL_PROJLIST, whichline);
2111 
2112 	DiaDimItem(dia, DPRL_CHECKOUT);
2113 	DiaDimItem(dia, DPRL_CHECKIN);
2114 	if (whichline >= 0)
2115 	{
2116 		if (*curpf->comment != 0) DiaSetText(dia, DPRL_COMMENTS, curpf->comment);
2117 		if (*curpf->owner == 0) DiaUnDimItem(dia, DPRL_CHECKOUT); else
2118 			DiaDimItem(dia, DPRL_CHECKOUT);
2119 		if (estrcmp(curpf->owner, proj_username) == 0) DiaUnDimItem(dia, DPRL_CHECKIN); else
2120 			DiaDimItem(dia, DPRL_CHECKIN);
2121 	}
2122 
2123 	if (uptodate) DiaDimItem(dia, DPRL_UPDATE); else
2124 	{
2125 		ttyputmsg(_("Your library does not contain the most recent additions to the project."));
2126 		ttyputmsg(_("You should do an 'Update' to make it current."));
2127 		DiaUnDimItem(dia, DPRL_UPDATE);
2128 	}
2129 	return(FALSE);
2130 }
2131 
2132 /* Project Comments */
2133 static DIALOGITEM proj_commentsdialogitems[] =
2134 {
2135  /*  1 */ {0, {104,244,128,308}, BUTTON, N_("OK")},
2136  /*  2 */ {0, {104,48,128,112}, BUTTON, N_("Cancel")},
2137  /*  3 */ {0, {4,8,20,363}, MESSAGE, N_("Reason for checking out cell")},
2138  /*  4 */ {0, {28,12,92,358}, EDITTEXT, x_("")}
2139 };
2140 static DIALOG proj_commentsdialog = {{108,75,248,447}, N_("Project Comments"), 0, 4, proj_commentsdialogitems, 0, 0};
2141 
2142 /* special items for the "Project list" dialog: */
2143 #define DPRC_COMMENT_L  3		/* Comment label (stat text) */
2144 #define DPRC_COMMENT    4		/* Comment (edit text) */
2145 
2146 /*
2147  * Routine to obtain comments about a checkin/checkout for cell "pf".  "direction" is
2148  * either "in" or "out".  Returns true if the dialog is cancelled.
2149  */
proj_getcomments(PROJECTCELL * pf,CHAR * direction)2150 BOOLEAN proj_getcomments(PROJECTCELL *pf, CHAR *direction)
2151 {
2152 	REGISTER INTBIG itemHit;
2153 	static CHAR line[256];
2154 	REGISTER void *dia;
2155 
2156 	dia = DiaInitDialog(&proj_commentsdialog);
2157 	if (dia == 0) return(TRUE);
2158 	esnprintf(line, 256, _("Reason for checking-%s cell %s"), direction, pf->cellname);
2159 	DiaSetText(dia, DPRC_COMMENT_L, line);
2160 	DiaSetText(dia, -DPRC_COMMENT, pf->comment);
2161 	for(;;)
2162 	{
2163 		itemHit = DiaNextHit(dia);
2164 		if (itemHit == CANCEL || itemHit == OK) break;
2165 	}
2166 	if (itemHit == OK)
2167 		(void)reallocstring(&pf->comment, DiaGetText(dia, DPRC_COMMENT), proj_tool->cluster);
2168 	DiaDoneDialog(dia);
2169 	if (itemHit == CANCEL) return(TRUE);
2170 	return(FALSE);
2171 }
2172 
2173 /************************ PROJECT FILE ***********************/
2174 
proj_readprojectfile(CHAR * pathname,CHAR * filename)2175 BOOLEAN proj_readprojectfile(CHAR *pathname, CHAR *filename)
2176 {
2177 	CHAR *truename, projline[256], *pt, *start, fullname[256], origprojline[256];
2178 	FILE *io;
2179 	REGISTER BOOLEAN err;
2180 	PROJECTCELL *pf, *pftail, *nextpf, *opf;
2181 
2182 	/* delete previous project database */
2183 	for(pf = proj_firstprojectcell; pf != NOPROJECTCELL; pf = nextpf)
2184 	{
2185 		nextpf = pf->nextprojectcell;
2186 		efree(pf->libname);
2187 		efree(pf->cellname);
2188 		efree(pf->owner);
2189 		efree(pf->lastowner);
2190 		efree(pf->comment);
2191 		proj_freeprojectcell(pf);
2192 	}
2193 
2194 	/* read the project file */
2195 	proj_firstprojectcell = pftail = NOPROJECTCELL;
2196 	estrcpy(fullname, pathname);
2197 	estrcat(fullname, filename);
2198 	io = xopen(fullname, proj_filetypeproj, x_(""), &truename);
2199 	if (io == 0)
2200 	{
2201 		ttyputerr(_("Couldn't read project file '%s'"), fullname);
2202 		return(TRUE);
2203 	}
2204 
2205 	err = FALSE;
2206 	for(;;)
2207 	{
2208 		if (xfgets(projline, 256, io)) break;
2209 		estrcpy(origprojline, projline);
2210 		pf = proj_allocprojectcell();
2211 		if (pf == 0) break;
2212 
2213 		pt = projline;
2214 		if (*pt++ != ':')
2215 		{
2216 			ttyputerr(_("Missing initial ':' in project file: '%s'"), origprojline);
2217 			err = TRUE;
2218 			break;
2219 		}
2220 
2221 		/* get library name */
2222 		for(start = pt; *pt != 0; pt++) if (*pt == ':') break;
2223 		if (*pt != ':')
2224 		{
2225 			ttyputerr(_("Missing ':' after library name in project file: '%s'"), origprojline);
2226 			err = TRUE;
2227 			break;
2228 		}
2229 		*pt++ = 0;
2230 		(void)allocstring(&pf->libname, start, proj_tool->cluster);
2231 
2232 		/* get cell name */
2233 		for(start = pt; *pt != 0; pt++) if (*pt == ':') break;
2234 		if (*pt != ':')
2235 		{
2236 			ttyputerr(_("Missing ':' after cell name in project file: '%s'"), origprojline);
2237 			err = TRUE;
2238 			break;
2239 		}
2240 		*pt++ = 0;
2241 		(void)allocstring(&pf->cellname, start, proj_tool->cluster);
2242 
2243 		/* get version */
2244 		pf->cellversion = eatoi(pt);
2245 		for( ; *pt != 0; pt++) if (*pt == '-') break;
2246 		if (*pt++ != '-')
2247 		{
2248 			ttyputerr(_("Missing '-' after version number in project file: '%s'"), origprojline);
2249 			err = TRUE;
2250 			break;
2251 		}
2252 
2253 		/* get view */
2254 		for(start = pt; *pt != 0; pt++)
2255 			if (pt[0] == '.' && pt[1] == 'e' && pt[2] == 'l' && pt[3] == 'i' && pt[4] == 'b' &&
2256 				pt[5] == ':') break;
2257 		if (*pt == 0)
2258 		{
2259 			ttyputerr(_("Missing '.elib' after view name in project file: '%s'"), origprojline);
2260 			err = TRUE;
2261 			break;
2262 		}
2263 		*pt = 0;
2264 		pt += 6;
2265 		pf->cellview = getview(start);
2266 
2267 		/* get owner */
2268 		for(start = pt; *pt != 0; pt++) if (*pt == ':') break;
2269 		if (*pt != ':')
2270 		{
2271 			ttyputerr(_("Missing ':' after owner name in project file: '%s'"), origprojline);
2272 			err = TRUE;
2273 			break;
2274 		}
2275 		*pt++ = 0;
2276 		(void)allocstring(&pf->owner, start, proj_tool->cluster);
2277 
2278 		/* get last owner */
2279 		for(start = pt; *pt != 0; pt++) if (*pt == ':') break;
2280 		if (*pt != ':')
2281 		{
2282 			ttyputerr(_("Missing ':' after last owner name in project file: '%s'"), origprojline);
2283 			err = TRUE;
2284 			break;
2285 		}
2286 		*pt++ = 0;
2287 		(void)allocstring(&pf->lastowner, start, proj_tool->cluster);
2288 
2289 		/* get comments */
2290 		(void)allocstring(&pf->comment, pt, proj_tool->cluster);
2291 
2292 		/* check for duplication */
2293 		for(opf = proj_firstprojectcell; opf != NOPROJECTCELL; opf = opf->nextprojectcell)
2294 		{
2295 			if (namesame(opf->cellname, pf->cellname) != 0) continue;
2296 			if (opf->cellview != pf->cellview) continue;
2297 			ttyputerr(_("Error in project file: view '%s' of cell '%s' exists twice (versions %ld and %ld)"),
2298 				pf->cellview->viewname, pf->cellname, pf->cellversion, opf->cellversion);
2299 		}
2300 
2301 		/* link it in */
2302 		pf->nextprojectcell = NOPROJECTCELL;
2303 		if (proj_firstprojectcell == NOPROJECTCELL) proj_firstprojectcell = pftail = pf; else
2304 		{
2305 			pftail->nextprojectcell = pf;
2306 			pftail = pf;
2307 		}
2308 	}
2309 	xclose(io);
2310 	return(err);
2311 }
2312 
proj_startwritingprojectfile(CHAR * pathname,CHAR * filename)2313 BOOLEAN proj_startwritingprojectfile(CHAR *pathname, CHAR *filename)
2314 {
2315 	CHAR *truename, fullname[256];
2316 
2317 	/* read the project file */
2318 	estrcpy(fullname, pathname);
2319 	estrcat(fullname, filename);
2320 	proj_io = xopen(fullname, proj_filetypeproj | FILETYPEWRITE, x_(""), &truename);
2321 	if (proj_io == 0)
2322 	{
2323 		ttyputerr(_("Couldn't write project file '%s'"), fullname);
2324 		return(TRUE);
2325 	}
2326 	return(FALSE);
2327 }
2328 
proj_endwritingprojectfile(void)2329 void proj_endwritingprojectfile(void)
2330 {
2331 	PROJECTCELL *pf;
2332 
2333 	for(pf = proj_firstprojectcell; pf != NOPROJECTCELL; pf = pf->nextprojectcell)
2334 		xprintf(proj_io, x_(":%s:%s:%ld-%s.elib:%s:%s:%s\n"), pf->libname, pf->cellname,
2335 			pf->cellversion, pf->cellview->viewname, pf->owner, pf->lastowner, pf->comment);
2336 	xclose(proj_io);
2337 	noundoallowed();
2338 }
2339 
proj_allocprojectcell(void)2340 PROJECTCELL *proj_allocprojectcell(void)
2341 {
2342 	PROJECTCELL *pf;
2343 
2344 	if (proj_projectcellfree != NOPROJECTCELL)
2345 	{
2346 		pf = proj_projectcellfree;
2347 		proj_projectcellfree = proj_projectcellfree->nextprojectcell;
2348 	} else
2349 	{
2350 		pf = (PROJECTCELL *)emalloc(sizeof (PROJECTCELL), proj_tool->cluster);
2351 		if (pf == 0) return(0);
2352 	}
2353 	return(pf);
2354 }
2355 
proj_freeprojectcell(PROJECTCELL * pf)2356 void proj_freeprojectcell(PROJECTCELL *pf)
2357 {
2358 	pf->nextprojectcell = proj_projectcellfree;
2359 	proj_projectcellfree = pf;
2360 }
2361 
proj_findcell(NODEPROTO * np)2362 PROJECTCELL *proj_findcell(NODEPROTO *np)
2363 {
2364 	PROJECTCELL *pf;
2365 
2366 	for(pf = proj_firstprojectcell; pf != NOPROJECTCELL; pf = pf->nextprojectcell)
2367 		if (estrcmp(pf->cellname, np->protoname) == 0 && pf->cellview == np->cellview)
2368 			return(pf);
2369 	return(NOPROJECTCELL);
2370 }
2371 
2372 /************************ LOCKING ***********************/
2373 
2374 #define MAXTRIES 10
2375 #define NAPTIME  5
2376 
proj_lockprojfile(CHAR * projectpath,CHAR * projectfile)2377 BOOLEAN proj_lockprojfile(CHAR *projectpath, CHAR *projectfile)
2378 {
2379 	CHAR lockfilename[256];
2380 	REGISTER INTBIG i, j;
2381 
2382 	esnprintf(lockfilename, 256, x_("%s%sLOCK"), projectpath, projectfile);
2383 	for(i=0; i<MAXTRIES; i++)
2384 	{
2385 		if (lockfile(lockfilename)) return(FALSE);
2386 		if (i == 0) ttyputmsg(_("Project file locked.  Waiting...")); else
2387 			ttyputmsg(_("Still waiting (will try %d more times)..."), MAXTRIES-i);
2388 		for(j=0; j<NAPTIME; j++)
2389 		{
2390 			gotosleep(60);
2391 			if (stopping(STOPREASONLOCK)) return(TRUE);
2392 		}
2393 	}
2394 	return(TRUE);
2395 }
2396 
proj_unlockprojfile(CHAR * projectpath,CHAR * projectfile)2397 void proj_unlockprojfile(CHAR *projectpath, CHAR *projectfile)
2398 {
2399 	CHAR lockfilename[256];
2400 
2401 	esnprintf(lockfilename, 256, x_("%s%sLOCK"), projectpath, projectfile);
2402 	unlockfile(lockfilename);
2403 }
2404 
proj_validatelocks(LIBRARY * lib)2405 void proj_validatelocks(LIBRARY *lib)
2406 {
2407 	REGISTER NODEPROTO *np;
2408 	PROJECTCELL *pf;
2409 
2410 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2411 	{
2412 		pf = proj_findcell(np);
2413 		if (pf == NOPROJECTCELL)
2414 		{
2415 			/* cell not in the project: writable */
2416 			proj_marklocked(np, FALSE);
2417 		} else
2418 		{
2419 			if (np->version < pf->cellversion)
2420 			{
2421 				/* cell is an old version: writable */
2422 				proj_marklocked(np, FALSE);
2423 			} else
2424 			{
2425 				if (namesame(pf->owner, proj_username) == 0)
2426 				{
2427 					/* cell checked out to current user: writable */
2428 					proj_marklocked(np, FALSE);
2429 				} else
2430 				{
2431 					/* cell checked out to someone else: not writable */
2432 					proj_marklocked(np, TRUE);
2433 				}
2434 			}
2435 		}
2436 	}
2437 }
2438 
proj_marklocked(NODEPROTO * np,BOOLEAN locked)2439 void proj_marklocked(NODEPROTO *np, BOOLEAN locked)
2440 {
2441 	REGISTER NODEPROTO *onp;
2442 
2443 	if (!locked)
2444 	{
2445 		FOR_CELLGROUP(onp, np)
2446 		{
2447 			if (onp->cellview != np->cellview) continue;
2448 			if (getvalkey((INTBIG)onp, VNODEPROTO, VINTEGER, proj_lockedkey) != NOVARIABLE)
2449 				(void)delvalkey((INTBIG)onp, VNODEPROTO, proj_lockedkey);
2450 		}
2451 	} else
2452 	{
2453 		FOR_CELLGROUP(onp, np)
2454 		{
2455 			if (onp->cellview != np->cellview) continue;
2456 			if (onp->newestversion == onp)
2457 			{
2458 				if (getvalkey((INTBIG)onp, VNODEPROTO, VINTEGER, proj_lockedkey) == NOVARIABLE)
2459 					setvalkey((INTBIG)onp, VNODEPROTO, proj_lockedkey, 1, VINTEGER);
2460 			} else
2461 			{
2462 				if (getvalkey((INTBIG)onp, VNODEPROTO, VINTEGER, proj_lockedkey) != NOVARIABLE)
2463 					(void)delvalkey((INTBIG)onp, VNODEPROTO, proj_lockedkey);
2464 			}
2465 		}
2466 	}
2467 }
2468 
2469 /************************ CHANGE TRACKING ***********************/
2470 
proj_queuecheck(NODEPROTO * cell)2471 void proj_queuecheck(NODEPROTO *cell)
2472 {
2473 	REGISTER FCHECK *f;
2474 
2475 	/* see if the cell is already queued */
2476 	for(f = proj_firstfcheck; f != NOFCHECK; f = f->nextfcheck)
2477 		if (f->entry == cell && f->batchnumber == proj_batchnumber) return;
2478 
2479 	/* code cannot be called by multiple procesors: uses globals */
2480 	NOT_REENTRANT;
2481 
2482 	f = proj_allocfcheck();
2483 	if (f == NOFCHECK)
2484 	{
2485 		ttyputnomemory();
2486 		return;
2487 	}
2488 	f->entry = cell;
2489 	f->batchnumber = proj_batchnumber;
2490 	f->nextfcheck = proj_firstfcheck;
2491 	proj_firstfcheck = f;
2492 }
2493 
proj_allocfcheck(void)2494 FCHECK *proj_allocfcheck(void)
2495 {
2496 	REGISTER FCHECK *f;
2497 
2498 	/* code cannot be called by multiple procesors: uses globals */
2499 	NOT_REENTRANT;
2500 
2501 	if (proj_fcheckfree == NOFCHECK)
2502 	{
2503 		f = (FCHECK *)emalloc((sizeof (FCHECK)), proj_tool->cluster);
2504 		if (f == 0) return(NOFCHECK);
2505 	} else
2506 	{
2507 		f = proj_fcheckfree;
2508 		proj_fcheckfree = f->nextfcheck;
2509 	}
2510 
2511 	return(f);
2512 }
2513 
proj_freefcheck(FCHECK * f)2514 void proj_freefcheck(FCHECK *f)
2515 {
2516 	f->nextfcheck = proj_fcheckfree;
2517 	proj_fcheckfree = f;
2518 }
2519 
2520 /************************ COPYING CELLS IN AND OUT OF DATABASE ***********************/
2521 
2522 /*
2523  * Routine to get the latest version of the cell described by "pf" and return
2524  * the newly created cell.  Returns NONODEPROTO on error.
2525  */
proj_getcell(PROJECTCELL * pf,LIBRARY * lib)2526 NODEPROTO *proj_getcell(PROJECTCELL *pf, LIBRARY *lib)
2527 {
2528 	CHAR celllibname[256], celllibpath[256], cellprojfile[256], cellname[256],
2529 		*templibname;
2530 	REGISTER LIBRARY *flib;
2531 	REGISTER NODEPROTO *newnp;
2532 	REGISTER INTBIG oldverbose, ret;
2533 
2534 	/* create the library */
2535 	if (proj_getprojinfo(lib, celllibpath, cellprojfile))
2536 	{
2537 		ttyputerr(_("Cannot find project info on library %s"), lib->libname);
2538 		return(NONODEPROTO);
2539 	}
2540 	esnprintf(celllibname, 256, x_("%ld-%s.elib"), pf->cellversion, pf->cellview->viewname);
2541 	cellprojfile[estrlen(cellprojfile)-5] = 0;
2542 	estrcat(celllibpath, cellprojfile);
2543 	estrcat(celllibpath, DIRSEPSTR);
2544 	estrcat(celllibpath, pf->cellname);
2545 	estrcat(celllibpath, DIRSEPSTR);
2546 	estrcat(celllibpath, celllibname);
2547 
2548 	/* prevent tools (including this one) from seeing the change */
2549 	(void)proj_turnofftools();
2550 
2551 	templibname = proj_templibraryname();
2552 	flib = newlibrary(templibname, celllibpath);
2553 	if (flib == NOLIBRARY)
2554 	{
2555 		ttyputerr(_("Cannot create library %s"), celllibpath);
2556 		proj_restoretoolstate();
2557 		return(NONODEPROTO);
2558 	}
2559 	oldverbose = asktool(io_tool, x_("verbose"), 0);
2560 	ret = asktool(io_tool, x_("read"), (INTBIG)flib, (INTBIG)x_("binary"));
2561 	(void)asktool(io_tool, x_("verbose"), oldverbose);
2562 	if (ret != 0)
2563 	{
2564 		ttyputerr(_("Cannot read library %s"), celllibpath);
2565 		killlibrary(flib);
2566 		proj_restoretoolstate();
2567 		return(NONODEPROTO);
2568 	}
2569 	if (flib->curnodeproto == NONODEPROTO)
2570 	{
2571 		ttyputerr(_("Cannot find cell in library %s"), celllibpath);
2572 		killlibrary(flib);
2573 		proj_restoretoolstate();
2574 		return(NONODEPROTO);
2575 	}
2576 	esnprintf(cellname, 256, x_("%s;%ld"), flib->curnodeproto->protoname, flib->curnodeproto->version);
2577 	if (flib->curnodeproto->cellview != el_unknownview)
2578 	{
2579 		estrcat(cellname, x_("{"));
2580 		estrcat(cellname, flib->curnodeproto->cellview->sviewname);
2581 		estrcat(cellname, x_("}"));
2582 	}
2583 	newnp = copynodeproto(flib->curnodeproto, lib, cellname, TRUE);
2584 	if (newnp == NONODEPROTO)
2585 	{
2586 		ttyputerr(_("Cannot copy cell %s from new library"), describenodeproto(flib->curnodeproto));
2587 		killlibrary(flib);
2588 		proj_restoretoolstate();
2589 		return(NONODEPROTO);
2590 	}
2591 	(*el_curconstraint->solve)(newnp);
2592 
2593 	/* must do this explicitly because the library kill flushes change batches */
2594 	/* (void)asktool(net_tool, "re-number", (INTBIG)newnp); */
2595 
2596 	/* kill the library */
2597 	killlibrary(flib);
2598 
2599 	/* restore tool state */
2600 	proj_restoretoolstate();
2601 
2602 	/* return the new cell */
2603 	return(newnp);
2604 }
2605 
proj_usenewestversion(NODEPROTO * oldnp,NODEPROTO * newnp)2606 BOOLEAN proj_usenewestversion(NODEPROTO *oldnp, NODEPROTO *newnp)
2607 {
2608 	INTBIG lx, hx, ly, hy;
2609 	REGISTER WINDOWPART *w;
2610 	REGISTER LIBRARY *lib;
2611 	REGISTER NODEINST *ni, *newni, *nextni;
2612 
2613 	/* prevent tools (including this one) from seeing the change */
2614 	(void)proj_turnofftools();
2615 
2616 	/* replace them all */
2617 	for(ni = oldnp->firstinst; ni != NONODEINST; ni = nextni)
2618 	{
2619 		nextni = ni->nextinst;
2620 		newni = replacenodeinst(ni, newnp, FALSE, FALSE);
2621 		if (newni == NONODEINST)
2622 		{
2623 			ttyputerr(_("Failed to update instance of %s in %s"), describenodeproto(newnp),
2624 				describenodeproto(ni->parent));
2625 			proj_restoretoolstate();
2626 			return(TRUE);
2627 		}
2628 	}
2629 
2630 	/* redraw windows that updated */
2631 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2632 	{
2633 		if (w->curnodeproto == NONODEPROTO) continue;
2634 		if (w->curnodeproto != newnp) continue;
2635 		w->curnodeproto = newnp;
2636 
2637 		/* redisplay the window with the new cell */
2638 		us_fullview(newnp, &lx, &hx, &ly, &hy);
2639 		us_squarescreen(w, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 0);
2640 		startobjectchange((INTBIG)w, VWINDOWPART);
2641 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenlx"), lx, VINTEGER);
2642 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenhx"), hx, VINTEGER);
2643 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenly"), ly, VINTEGER);
2644 		(void)setval((INTBIG)w, VWINDOWPART, x_("screenhy"), hy, VINTEGER);
2645 		us_gridset(w, w->state);
2646 		endobjectchange((INTBIG)w, VWINDOWPART);
2647 	}
2648 
2649 	/* update status display if necessary */
2650 	if (us_curnodeproto == oldnp) us_setnodeproto(newnp);
2651 
2652 	/* replace library references */
2653 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
2654 		if (lib->curnodeproto == oldnp)
2655 			(void)setval((INTBIG)lib, VLIBRARY, x_("curnodeproto"), (INTBIG)newnp, VNODEPROTO);
2656 
2657 	if (killnodeproto(oldnp))
2658 		ttyputerr(_("Could not delete old version"));
2659 
2660 	/* restore tool state */
2661 	proj_restoretoolstate();
2662 	return(FALSE);
2663 }
2664 
proj_writecell(NODEPROTO * np)2665 BOOLEAN proj_writecell(NODEPROTO *np)
2666 {
2667 	REGISTER LIBRARY *flib;
2668 	REGISTER INTBIG retval;
2669 	CHAR libname[256], libfile[256], projname[256], *templibname;
2670 	REGISTER NODEPROTO *npcopy;
2671 	INTBIG filestatus;
2672 
2673 	if (proj_getprojinfo(np->lib, libfile, projname))
2674 	{
2675 		ttyputerr(_("Cannot find project info on library %s"), np->lib->libname);
2676 		return(TRUE);
2677 	}
2678 	projname[estrlen(projname)-5] = 0;
2679 	estrcat(libfile, projname);
2680 	estrcat(libfile, DIRSEPSTR);
2681 	estrcat(libfile, np->protoname);
2682 
2683 	/* make the directory if necessary */
2684 	filestatus = fileexistence(libfile);
2685 	if (filestatus == 1 || filestatus == 3)
2686 	{
2687 		ttyputerr(_("Could not create cell directory '%s'"), libfile);
2688 		return(TRUE);
2689 	}
2690 	if (filestatus == 0)
2691 	{
2692 		if (createdirectory(libfile))
2693 		{
2694 			ttyputerr(_("Could not create cell directory '%s'"), libfile);
2695 			return(TRUE);
2696 		}
2697 	}
2698 
2699 	estrcat(libfile, DIRSEPSTR);
2700 	esnprintf(libname, 256, x_("%ld-%s.elib"), np->version, np->cellview->viewname);
2701 	estrcat(libfile, libname);
2702 
2703 	/* prevent tools (including this one) from seeing the change */
2704 	(void)proj_turnofftools();
2705 
2706 	templibname = proj_templibraryname();
2707 	flib = newlibrary(templibname, libfile);
2708 	if (flib == NOLIBRARY)
2709 	{
2710 		ttyputerr(_("Cannot create library %s"), libfile);
2711 		proj_restoretoolstate();
2712 		return(TRUE);
2713 	}
2714 	npcopy = copyrecursively(np, flib);
2715 	if (npcopy == NONODEPROTO)
2716 	{
2717 		ttyputerr(_("Could not place %s in a library"), describenodeproto(np));
2718 		killlibrary(flib);
2719 		proj_restoretoolstate();
2720 		return(TRUE);
2721 	}
2722 
2723 	flib->curnodeproto = npcopy;
2724 	flib->userbits |= READFROMDISK;
2725 	makeoptionstemporary(flib);
2726 	retval = asktool(io_tool, x_("write"), (INTBIG)flib, (INTBIG)x_("binary"));
2727 	restoreoptionstate(flib);
2728 	if (retval != 0)
2729 	{
2730 		ttyputerr(_("Could not save library with %s in it"), describenodeproto(np));
2731 		killlibrary(flib);
2732 		proj_restoretoolstate();
2733 		return(TRUE);
2734 	}
2735 	killlibrary(flib);
2736 
2737 	/* restore tool state */
2738 	proj_restoretoolstate();
2739 
2740 	return(FALSE);
2741 }
2742 
proj_templibraryname(void)2743 CHAR *proj_templibraryname(void)
2744 {
2745 	static CHAR libname[256];
2746 	REGISTER LIBRARY *lib;
2747 	REGISTER INTBIG i;
2748 
2749 	for(i=1; ; i++)
2750 	{
2751 		esnprintf(libname, 256, x_("projecttemp%ld"), i);
2752 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
2753 			if (namesame(libname, lib->libname) == 0) break;
2754 		if (lib == NOLIBRARY) break;
2755 	}
2756 	return(libname);
2757 }
2758 
2759 /*
2760  * Routine to save the state of all tools and turn them off.
2761  */
proj_turnofftools(void)2762 BOOLEAN proj_turnofftools(void)
2763 {
2764 	REGISTER INTBIG i;
2765 	REGISTER TOOL *tool;
2766 
2767 	/* turn off all tools for this operation */
2768 	if (proj_savetoolstate == 0)
2769 	{
2770 		proj_savetoolstate = (INTBIG *)emalloc(el_maxtools * SIZEOFINTBIG, el_tempcluster);
2771 		if (proj_savetoolstate == 0) return(TRUE);
2772 	}
2773 	for(i=0; i<el_maxtools; i++)
2774 	{
2775 		tool = &el_tools[i];
2776 		proj_savetoolstate[i] = tool->toolstate;
2777 		if (tool == us_tool || tool == proj_tool || tool == net_tool) continue;
2778 		tool->toolstate &= ~TOOLON;
2779 	}
2780 	proj_ignorechanges = TRUE;
2781 	return(FALSE);
2782 }
2783 
2784 /*
2785  * Routine to restore the state of all tools that were reset by "proj_turnofftools()".
2786  */
proj_restoretoolstate(void)2787 void proj_restoretoolstate(void)
2788 {
2789 	REGISTER INTBIG i;
2790 
2791 	if (proj_savetoolstate == 0) return;
2792 	for(i=0; i<el_maxtools; i++)
2793 		el_tools[i].toolstate = proj_savetoolstate[i];
2794 	proj_ignorechanges = FALSE;
2795 }
2796 
2797 /************************ DATABASE OPERATIONS ***********************/
2798 
copyrecursively(NODEPROTO * fromnp,LIBRARY * tolib)2799 NODEPROTO *copyrecursively(NODEPROTO *fromnp, LIBRARY *tolib)
2800 {
2801 	REGISTER NODEPROTO *np, *onp, *newfromnp;
2802 	REGISTER NODEINST *ni;
2803 	REGISTER CHAR *newname;
2804 	CHAR versnum[20];
2805 	REGISTER void *infstr;
2806 
2807 	/* must copy subcells */
2808 	for(ni = fromnp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2809 	{
2810 		np = ni->proto;
2811 		if (np->primindex != 0) continue;
2812 
2813 		/* see if there is already a cell with this name and view */
2814 		for(onp = tolib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
2815 			if (namesame(onp->protoname, np->protoname) == 0 &&
2816 				onp->cellview == np->cellview) break;
2817 		if (onp != NONODEPROTO) continue;
2818 
2819 		onp = copyskeleton(np, tolib);
2820 		if (onp == NONODEPROTO)
2821 		{
2822 			ttyputerr(_("Copy of subcell %s failed"), describenodeproto(np));
2823 			return(NONODEPROTO);
2824 		}
2825 	}
2826 
2827 	/* copy the cell if it is not already done */
2828 	for(newfromnp = tolib->firstnodeproto; newfromnp != NONODEPROTO; newfromnp = newfromnp->nextnodeproto)
2829 		if (namesame(newfromnp->protoname, fromnp->protoname) == 0 &&
2830 			newfromnp->cellview == fromnp->cellview && newfromnp->version == fromnp->version) break;
2831 	if (newfromnp == NONODEPROTO)
2832 	{
2833 		infstr = initinfstr();
2834 		addstringtoinfstr(infstr, fromnp->protoname);
2835 		addtoinfstr(infstr, ';');
2836 		esnprintf(versnum, 20, x_("%ld"), fromnp->version);
2837 		addstringtoinfstr(infstr, versnum);
2838 		if (fromnp->cellview != el_unknownview)
2839 		{
2840 			addtoinfstr(infstr, '{');
2841 			addstringtoinfstr(infstr, fromnp->cellview->sviewname);
2842 			addtoinfstr(infstr, '}');
2843 		}
2844 		newname = returninfstr(infstr);
2845 		newfromnp = copynodeproto(fromnp, tolib, newname, TRUE);
2846 		if (newfromnp == NONODEPROTO) return(NONODEPROTO);
2847 
2848 		/* ensure that the copied cell is the right size */
2849 		(*el_curconstraint->solve)(newfromnp);
2850 	}
2851 
2852 	return(newfromnp);
2853 }
2854 
copyskeleton(NODEPROTO * fromnp,LIBRARY * tolib)2855 NODEPROTO *copyskeleton(NODEPROTO *fromnp, LIBRARY *tolib)
2856 {
2857 	CHAR *newname;
2858 	REGISTER INTBIG newang, newtran;
2859 	REGISTER INTBIG i, xc, yc;
2860 	INTBIG newx, newy;
2861 	XARRAY trans, localtrans, ntrans;
2862 	REGISTER NODEPROTO *np;
2863 	REGISTER PORTPROTO *pp, *rpp;
2864 	REGISTER NODEINST *ni, *newni;
2865 	REGISTER void *infstr;
2866 
2867 	/* cannot skeletonize text-only views */
2868 	if ((fromnp->cellview->viewstate&TEXTVIEW) != 0) return(NONODEPROTO);
2869 
2870 	infstr = initinfstr();
2871 	addstringtoinfstr(infstr, fromnp->protoname);
2872 	if (fromnp->cellview != el_unknownview)
2873 	{
2874 		addtoinfstr(infstr, '{');
2875 		addstringtoinfstr(infstr, fromnp->cellview->sviewname);
2876 		addtoinfstr(infstr, '}');
2877 	}
2878 	newname = returninfstr(infstr);
2879 	np = newnodeproto(newname, tolib);
2880 	if (np == NONODEPROTO) return(NONODEPROTO);
2881 
2882 	/* place all exports in the new cell */
2883 	for(pp = fromnp->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2884 	{
2885 		/* make a transformation matrix for the node that has exports */
2886 		ni = pp->subnodeinst;
2887 		rpp = pp->subportproto;
2888 		newang = ni->rotation;
2889 		newtran = ni->transpose;
2890 		makerot(ni, trans);
2891 		while (ni->proto->primindex == 0)
2892 		{
2893 			maketrans(ni, localtrans);
2894 			transmult(localtrans, trans, ntrans);
2895 			ni = rpp->subnodeinst;
2896 			rpp = rpp->subportproto;
2897 			if (ni->transpose == 0) newang = ni->rotation + newang; else
2898 				newang = ni->rotation + 3600 - newang;
2899 			newtran = (newtran + ni->transpose) & 1;
2900 			makerot(ni, localtrans);
2901 			transmult(localtrans, ntrans, trans);
2902 		}
2903 
2904 		/* create this node */
2905 		xc = (ni->lowx + ni->highx) / 2;   yc = (ni->lowy + ni->highy) / 2;
2906 		xform(xc, yc, &newx, &newy, trans);
2907 		newx -= (ni->highx - ni->lowx) / 2;
2908 		newy -= (ni->highy - ni->lowy) / 2;
2909 		newang = newang % 3600;   if (newang < 0) newang += 3600;
2910 		newni = newnodeinst(ni->proto, newx, newx+ni->highx-ni->lowx,
2911 			newy, newy+ni->highy-ni->lowy, newtran, newang, np);
2912 		if (newni == NONODEINST) return(NONODEPROTO);
2913 		endobjectchange((INTBIG)newni, VNODEINST);
2914 
2915 		/* export the port from the node */
2916 		(void)newportproto(np, newni, rpp, pp->protoname);
2917 	}
2918 
2919 	/* make sure cell is the same size */
2920 	i = (fromnp->highy+fromnp->lowy)/2 - (gen_invispinprim->highy-gen_invispinprim->lowy)/2;
2921 	(void)newnodeinst(gen_invispinprim, fromnp->lowx, fromnp->lowx+gen_invispinprim->highx-gen_invispinprim->lowx,
2922 		i, i+gen_invispinprim->highy-gen_invispinprim->lowy, 0, 0, np);
2923 
2924 	i = (fromnp->highy+fromnp->lowy)/2 - (gen_invispinprim->highy-gen_invispinprim->lowy)/2;
2925 	(void)newnodeinst(gen_invispinprim, fromnp->highx-(gen_invispinprim->highx-gen_invispinprim->lowx), fromnp->highx,
2926 		i, i+gen_invispinprim->highy-gen_invispinprim->lowy, 0, 0, np);
2927 
2928 	i = (fromnp->highx+fromnp->lowx)/2 - (gen_invispinprim->highx-gen_invispinprim->lowx)/2;
2929 	(void)newnodeinst(gen_invispinprim, i, i+gen_invispinprim->highx-gen_invispinprim->lowx,
2930 		fromnp->lowy, fromnp->lowy+gen_invispinprim->highy-gen_invispinprim->lowy, 0, 0, np);
2931 
2932 	i = (fromnp->highx+fromnp->lowx)/2 - (gen_invispinprim->highx-gen_invispinprim->lowx)/2;
2933 	(void)newnodeinst(gen_invispinprim, i, i+gen_invispinprim->highx-gen_invispinprim->lowx,
2934 		fromnp->highy-(gen_invispinprim->highy-gen_invispinprim->lowy), fromnp->highy, 0, 0,np);
2935 
2936 	(*el_curconstraint->solve)(np);
2937 	return(np);
2938 }
2939 
2940 #endif  /* PROJECTTOOL - at top */
2941