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