I would like to be able to change the Baseline attribute for all outlinks from a source module. Does anyone know of some DXL code that could be used to do this?
There must be an easier way rather than manually deleting previous outlinks (i.e. ModuleVersion BL [1.20] and recreating outlinks to a specific new baseline (i.e. ModuleVersion BL [1.21]).
for outLink in all (Object srcObject) -> (string linkModName) do {
...
targetVersion(outLink) ...
}
Thanks for any help.
Here is the dxl way to do it:
Link ol
Object o
Object othero
Module m = current
string LinkModName = "FULLPATHTOLINKMODULE"
Module tMod
ModName_ tModName
ModuleVersion mv
Baseline b
int tAbs
// Current Version of the Links
string cVersion = "1.20"
// Target Major, Minor and Suffix
int tMajor = 1
int tMinor = 21
string tSuffix = ""
for o in m do
{
for ol in all(o -> LinkModName) do
{
mv = targetVersion(ol)
tModName = target(ol)
tMod = read(fullName(tModName),false)
if(isBaseline(mv))
{
if(versionString(mv) "" == cVersion)
{
if(!isBaseline(tMod))
{
b = baseline(tMajor,tMinor,tSuffix)
if(baselineExists(tMod,b))
{
tMod = load(tMod, b, true)
} else {
ack "Baseline [" tMajor "." tMinor " " tSuffix "] was not found"
halt
}
}
tAbs = targetAbsNo(ol)
othero = object(tAbs,tMod)
if(!null othero)
{
o -> LinkModName -> othero
delete ol
}
}
}
}
}
flushDeletions()
save m
Don't forget to insert the path to your link module and update the baseline information for the current and target if necessary.
You can omit the delete ol and flushDeletions() if you decide not to remove the old links.
Related
I'm using the Analysis Wizard to create a LayoutDXL column which should list attributes (e.g. AbsoluteNumber) for each existing In-link in my current module. In one particular DOORS module, the resulting DXL code displays each of these attributes twice. This doesn't happen in other modules.
I did notice that the offending module doesn't have a defined set of LinkModules (as seen in File/ModuleProperties). Could that be causing some sort of loopback?
Update:
I've discovered that somehow the DXL code "thinks" there are two versions of a defined LinkModule, i.e. "Current" and "Baseline X" . These each link to different baseline numbers in the target DOORS module. I don't know how to fix that.
For reference, here's the DXL code generated with the Wizard. This is DOORS 9.6.1.11
// DXL generated by DOORS traceability wizard on 12 February 2019.
// Wizard version 2.0, DOORS version 9.6.1.11
pragma runLim, 0
string limitModules[1] = {"[serial number redacted]"}
void showIn(Object o, int depth) {
Link l
LinkRef lr
ModName_ otherMod = null
Module linkMod = null
ModuleVersion otherVersion = null
Object othero
string disp = null
string s = null
string plain, plainDisp
int plainTextLen
int count
bool doneOne = false
string linkModName = "*"
for lr in all(o<-linkModName) do {
otherMod = module (sourceVersion lr)
if (!null otherMod) {
if ((!isDeleted otherMod) && (null data(sourceVersion lr))) {
if (!equal(getItem otherMod, (itemFromID limitModules[depth-1]))) continue
load((sourceVersion lr),false)
}
}
}
for l in all(o<-linkModName) do {
otherVersion = sourceVersion l
otherMod = module(otherVersion)
if (null otherMod || isDeleted otherMod) continue
if (!equal(getItem otherMod, (itemFromID limitModules[depth-1]))) continue
othero = source l
if (null othero) {
load(otherVersion,false)
}
othero = source l
if (null othero) continue
if (isDeleted othero) continue
doneOne = true
if (depth == 1) {
s = probeRichAttr_(othero,"Absolute Number", false)
if (s == "")
displayRich("\\pard " " ")
else
displayRich("\\pard " s)
s = probeRichAttr_(othero,"Object Heading", false)
if (s == "")
displayRich("\\pard " " ")
else
displayRich("\\pard " s)
}
}
}
showIn(obj,1)
I've seen the situation where objects DID have two links between them, this is possible with different link modules (Object 1 of Module A SATISFIES Object 2 of Module B and Object 1 of Module A REFINES Object 2 of Module B). While there may be reasons for such a situation, most often this is caused by a "link move" script that was not used correctly.
You should augment your code by displaying the name of the link module as well (variable linkModName). Perhaps this shows the reason for your observation
I have a module A with objects linked from objects in another module B. In a view of A, I have a layout DXL column which lists all those linked B objects:
// DXL generated by DOORS traceability wizard on 02 May 2016.
// Wizard version 2.0, DOORS version 9.2.0.5
pragma runLim, 0
string limitModules[1] = {"40fedbf2697f0e24-00003921"}
void showIter(Object o, string linkModName, int depth, string build, string iter) {
Link l
Object othero
for l in all(o<-linkModName) do { // ****
otherVersion = sourceVersion l
otherMod = module(otherVersion)
if (null otherMod || isDeleted otherMod) continue
if (!equal(getItem otherMod, (itemFromID limitModules[depth-1]))) continue
othero = source l
if (null othero) {
load(otherVersion,false)
}
othero = source l
if (null othero) continue
if (isDeleted othero) continue
doneOne = true
if (depth == 1) {
disp = ""
obuild = probeRichAttr_(othero,"Build", false)
oiter = probeRichAttr_(othero,"Iteration (planned)", false)
string ocat = othero."Category"
if (obuild == build && oiter == iter) {
s = "(B" obuild "." oiter " - " ocat[0] ") " (identifier othero)
disp = disp s
s = probeRichAttr_(othero,"Object Text", false)
disp = disp " " s
displayRich("\\pard " disp)
}
}
}
}
void showIn(Object o, int depth) {
Link l
LinkRef lr
ModName_ otherMod = null
Module linkMod = null
ModuleVersion otherVersion = null
Object othero
string disp = null
string s = null
string plain, plainDisp
int plainTextLen
int count
bool doneOne = false
Item linkModItem = itemFromID("40fedbf2697f0e24-000039a3")
if (null linkModItem) {
displayRich("\\pard " "<<Link module not found>>")
} else if (type(linkModItem) != "Link") {
displayRich("\\pard " "<<Invalid link module index for this database>>")
} else {
string linkModName = fullName(linkModItem)
for lr in all(o<-linkModName) do {
otherMod = module (sourceVersion lr)
if (!null otherMod) {
if ((!isDeleted otherMod) && (null data(sourceVersion lr))) {
if (!equal(getItem otherMod, (itemFromID limitModules[depth-1]))) continue
load((sourceVersion lr),false)
}
}
}
//showIter(o, linkModName, depth, "1", "")
//showIter(o, linkModName, depth, "2", "")
showIter(o, linkModName, depth, "3", "3")
}
}
showIn(obj,1)
This script lists the linked objects in numerical order by object ID/key:
B object with ID# 3
B object with ID# 8
B object with ID# 21
B object with ID# 24
Yet in module B, without any sorting active, the objects are visible in insertion order, like this (i.e. according to where I made the insertion):
B object with ID# 24
B object with ID# 8
B object with ID# 21
B object with ID# 3
Is there a way to loop over B objects in insertion order, i.e. in order that they are displayed in B view when no sorting is active?
A "natural" order as you define it, is the order in which the source objects appear in the source module. This does not cover the case where source objects come from different modules, but this is just another problem..
A loop “.. for l in ....” has by definition no order defined, so in case you need one, you have to define your own order. In DXL, this is usually done by Skip lists.
You can create a skip list with the key being of type integer or string and the value being of type Link.
Then for each link, you can somehow calculate the correct order and add an entry where the key represents the order to the Skip list. A later loop „for l in skip“ will process the skip list in the order of the keys.
In your case, you can calculate the key by using a loop over all source objects, with the aid of a temporary skip list, like
int order = 0
Skip skOrderOfObject = create()
Object o
for o in entire (... source module...) do {
order ++
int absno = o."Absolute Number"
put (skOrderOfObject, order, absno)
}
Then to process each source object in your DXL column, you can do a
Skip skMySortedLinks = create()
...
for l in... {
Object oSource = source l
int iOrderOfThisObject
int absnoOfSource = oSource."Absolute Number"
find (skOrderOfObject, absnoOfSource, iOrderOfThisObject);
put (skMySortedLinks, iOrderOfThisObject, l)
}
and finally
Link l
for l in skMySortedLinks do {
... print whatever you want to print...
}
I'm new to DOORS and DXL scripting (not sure if it'll be needed here or not). What I'm looking to do is create a new column in two separate modules that will copy the Absolute Numbers. I know this sounds simple enough, but what I'm running into an issue with is that I use a tool to convert my modules into a PDF and it combines them into one module before doing so. Doing this messes up the Absolute Numbers and I can't afford to have that happen.
More descriptive:
I have a column that contains the following:
'REQ01: 4' where 'REQ01:' represents the module and '4' represents the Absolute Number. Similarly, I have 'REQ02: 4'. I need to copy those in their respective modules and make sure they don't change after the modules have been combined.
I've tried my hand at some DXL scripting and this is what I came up with:
displayRich("REQ01: " obj."Absolute Number" "")
This appropriately shows the column, but again will not work as the Absolute Number ends up changing when I merge the modules.
Thanks in advanced for your help and I apologize if I left any crucial information out.
Here is the code that ultimately worked for me.
// DXL generated on 11 June 2014 by Attribute DXL wizard, Version 1.0
// The wizard will use the following comments on subsequent runs
// to determine the selected options and attributes. It will not
// take account of any manual changes in the body of the DXL code.
// begin parameters (do not edit)
// One attribute/property per line: true
// Show attribute/property names: false
// Include OLE objects in text: true
// Attribute: Object Text
// end parameters (do not edit)
Module m
AttrDef ad
AttrType at
m = module obj
ad = find(m,attrDXLName)
if(!null ad && ad.object)
{
at = ad.type
if(at.type == attrText)
{
string s
Buffer val = create
Buffer temp = create
ad = find(m,"Object Text")
if(!null ad)
{
probeRichAttr_(obj,"Object Identifier", temp, true)
val += tempStringOf temp
}
obj.attrDXLName = richText (tempStringOf val)
delete val
delete temp
}
}
There's a builtin "Copy Attributes" script which does this. At least in the version installed at my company, it's in the PSToolbox, and also available in the menu PSToolbox/attributes/copy.../betweenattributes... Here you go:
// Copy values from one attribute to another
/*
*/
/*
PSToolbox Tools for customizing DOORS with DXL V7.1
-------------------------------------------------
DISCLAIMER:
This programming tool has been thoroughly checked
and tested at all stages of its production.
Telelogic cannot accept any responsibility for
any loss, disruption or damage to your data or
your computer system that may occur while using
this script.
If you do not accept these conditions, do not use
this customised script.
-------------------------------------------------
*/
if ( !confirm "This script copies values from one attribute to another in the same module.\n" //-
"Use this to assist in changing the types of attributes.\n\n" //-
"It asks you to select the source and destination attributes.\n\n" //-
"It works by ... well, copying attribute values!\n\n" //-
"Continue?"
)
{
halt
}
#include <addins/PSToolbox/utensils/dbs.inc>
const int MAXATTRS = 1000
DB copyAttrValsDB = null
DBE copyAttrValsFrom = null
DBE copyAttrValsTo = null
DBE copyAttrValsConfirm = null
DBE copyAttrValsButt = null
string attrListFrom[MAXATTRS]
string attrListTo[MAXATTRS]
string confirmOpts[] = { "Yes", "Yes to all", "No", "No to all", "Cancel" }
bool confirmDataLoss = true
bool noToDataLoss = false
///////////////////////////////////////////////////////////
// Call-backs
void doAttrValsCopy(DB db) {
// check attributes
string fromAn = attrListFrom[get copyAttrValsFrom]
string toAn = attrListTo [get copyAttrValsTo ]
if ( fromAn == toAn ) {
ack "Cannot copy attribute to itself."
return
}
// get confirmation
if ( !confirm "Confirm copy of attribute '" fromAn "' to attribute '" toAn "'." ) {
return
}
confirmDataLoss = get copyAttrValsConfirm
// do copy
Object o
for o in current Module do
{
Buffer oldVal = create()
Buffer newVal = create()
if ( fromAn == "Object Identifier" ) newVal = identifier(o)
else if ( fromAn == "Object Level" ) newVal = level(o) ""
else if ( fromAn == "Object Number" ) newVal = number(o)
else newVal = richText o.fromAn
oldVal = richText o.toAn
if ( confirmDataLoss && !noToDataLoss && length(oldVal) > 0 && oldVal != newVal )
{
current = o
refresh current
int opt = query("About to lose attribute '" toAn "' = '" stringOf(oldVal) "' on current object.", confirmOpts)
if ( opt == 1 ) confirmDataLoss = false
if ( opt == 2 ) continue
if ( opt == 3 ) noToDataLoss = true
if ( opt == 4 ) return
}
if ( !confirmDataLoss || !noToDataLoss || length(oldVal) == 0 ) o.toAn = richText stringOf(newVal)
delete(oldVal)
delete(newVal)
}
hide copyAttrValsDB
}
///////////////////////////////////////////////////////////
// Main program
int numAttrsFrom = 0
int numAttrsTo = 0
AttrDef ad
for ad in current Module do {
if ( ad.module ) continue
string an = ad.name
if ( canRead (current Module, an) ) attrListFrom[numAttrsFrom++] = an
if ( canWrite(current Module, an) ) attrListTo [numAttrsTo++ ] = an
}
attrListFrom[numAttrsFrom++] = "Object Identifier"
attrListFrom[numAttrsFrom++] = "Object Level"
attrListFrom[numAttrsFrom++] = "Object Number"
copyAttrValsDB = create "Copy attribute values"
copyAttrValsFrom = choice(copyAttrValsDB, "From:", attrListFrom, numAttrsFrom, 0)
copyAttrValsTo = choice(copyAttrValsDB, "To:", attrListTo, numAttrsTo, 0)
copyAttrValsButt = apply (copyAttrValsDB, "Copy", doAttrValsCopy)
copyAttrValsConfirm = toggle(copyAttrValsDB, "Confirm on loss of data", true)
show copyAttrValsDB
I'm working in a formal module with one type of in-links. These links (we call it as Type X links) are made in 4 depth level from 4 different formal modules. For example I'm working in module A, that have in-links from module B, that have in-links from module C, that have in-links from module D.
I have a view that shows in different columns each in-link level: Column 1: Depth 1 links (A-B), Column 2: Depth 2 links (B-C), Column 3: Depth 3 links (C-D).
Each column is generated by an script like this:
pragma runLim, 0
int lines[4] = {0, 0, 0, 0}
void adjustLines(int depth, showAtDepth) {
int count
for (count = 0; count < 4; count++) {
while (lines[depth-1] < lines[count]) {
if (depth == showAtDepth) displayRich("\\pard " " ")
lines[depth-1]++
}
}
}
void showIn(Object o, int depth) {
Link l
LinkRef lr
ModName_ otherMod = null
Module linkMod = null
ModuleVersion otherVersion = null
Object othero
string disp = null
string s = null
string plain, plainDisp
int plainTextLen
int count
bool doneOne = false
string linkModName = "../links/TYPE X"
for lr in all(o<-linkModName) do {
otherMod = module (sourceVersion lr)
if (!null otherMod) {
if ((!isDeleted otherMod) && (null data(sourceVersion lr))) {
load((sourceVersion lr),false)
}
}
}
for l in all(o<-linkModName) do {
otherVersion = sourceVersion l
otherMod = module(otherVersion)
if (null otherMod || isDeleted otherMod) continue
othero = source l
if (null othero) {
load(otherVersion,false)
}
othero = source l
if (null othero) continue
if (isDeleted othero) continue
int oldLines = lines[depth-1]
adjustLines(depth, 1)
bool kick = (doneOne) && (lines[depth-1] == oldLines)
if (kick) {
lines[depth-1]++
if (depth == 1) displayRich("\\pard " " ")
}
if (depth < 4) {
showIn(othero, depth+1)
}
doneOne = true
if (depth == 1) {
s = name(otherMod)
if (isBaseline(otherVersion)) {
s = s " [" versionString(otherVersion) "]"
}
s = "{\\b " s " : }"
s = s " " probeRichAttr_(othero,"Object Heading", false)
s = s " " probeRichAttr_(othero,"Object Text", false)
displayRich s
}
lines[depth-1] += 3
}
}
showIn(obj,1)
However now, I have to add a new column that contains other type of link (Type Y) defined between module C and other new module do not linked directly with my module (A). Fortunately, I have these relationship in a column at module C (as a layout dxl).
How can I show in my module (A) that column saved in a view at module (C) to be saved in my current view?
Thank you in advance for your cooperation and your help
Follow the Type X links to module C, and then follow Type Y links.
Change:
string linkModName = "../links/TYPE X"
To:
string linkModName = (depth<3) ? "../links/TYPE X" : "../links/TYPE Y"
You may need a different number as I'm not sure of you structure.
I was solving a problem in which given a linked list of characters , we have to move the vowels to the beginning such that both vowels and consonants are in chronological order. That is in the order in which they appear in original list.
Input : S->T->A->C->K->O->V->E->R->F->L->O->W
Output : A->O->E->O->S->T->C->K->V->R->F->L->W
I did it by traversing through the list once and created two lists called vowels and consonants and later merged them.
Can it be done without creating extra lists ? I mean in-place maybe using pointer manipulation?
Remember the beginning of the list. When you meet a vowel, move it to the beginning of the list; the vowel becomes the new beginning that you remember.
1. Traverse the list
2. When you encounter a vowel, check with head if its smaller or greater
3. If smaller, re-place new vowel before head, else move head and check again
4. In the end relocate head to first
temp = head;
while(current.next != null) {
if(current.isVowel()) {
if(head.isVowel()) {
//check the precedence
//Re-place the current with temp
}
else {
//Re-place current in front of head
}
}
current = current.next;
}
This is an abstract understanding. Implement it properly.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
struct list {
struct list *next;
int ch;
};
#define IS_VOWEL(p) strchr("aeiouy", tolower(p->ch))
struct list *shuffle ( struct list *lst )
{
struct list *new=NULL, **dst, **src;
dst = &new;
for (src = &lst; *src; ) {
struct list *this;
this= *src;
if (!IS_VOWEL(this)) { src= &(*src)->next; continue; }
*src = this->next;
this->next = *dst;
*dst = this;
dst = & (*dst)->next;
}
*dst = lst;
return new;
}
int main (void)
{
struct list arr[] = { {arr+1, 'S'} , {arr+2, 'T'} , {arr+3, 'A'}
, {arr+4, 'C'} , {arr+5, 'K'} , {arr+6, 'O'}
, {arr+7, 'V'} , {arr+8, 'E'} , {arr+9, 'R'}
, {arr+10, 'F'} , {arr+11, 'L'} , {arr+12, 'O'} , {NULL, 'W'} };
struct list *result;
result = shuffle (arr);
for ( ; result; result = result->next ) {
printf( "-> %c" , result->ch );
}
printf( "\n" );
return 0;
}
OUTPUT:
-> A-> O-> E-> O-> S-> T-> C-> K-> V-> R-> F-> L-> W
You can quite easily modify pointers to create two independent lists without actually having to duplicate any of the nodes, which is what I assume you mean when you say you want to avoid creating new lists. Only the pointers in the original nodes are modified.
First let's create the structures for the list:
#include <stdio.h>
#include <stdlib.h>
// Structure for singly linked list.
typedef struct sNode {
char ch;
struct sNode *next;
} tNode;
And next we provide two utility functions, the first to append a character to the list:
// Append to list, not very efficient but debug code anyway.
static tNode *append (tNode *head, char ch) {
// Allocate new node and populate it.
tNode *next = malloc (sizeof (tNode));
if (next == NULL) {
puts ("Out of memory");
exit (1);
}
next->ch = ch;
next->next = NULL;
// First in list, just return it.
if (head == NULL)
return next;
// Else get last, adjust pointer and return head.
tNode *this = head;
while (this->next != NULL)
this = this->next;
this->next = next;
return head;
}
And the second to dump a list for debugging purposes:
// Debug code to dump a list.
static void dump (tNode *this) {
if (this == NULL)
return;
printf ("(%08x)%c", this, this->ch);
while ((this = this->next) != NULL)
printf (" -> (%08x)%c", this, this->ch);
putchar ('\n');
}
Beyond that, we need an easy way to tell if a node is a vowel or not. For our purposes, we'll only use uppercase letters:
// Check for vowel (uppercase only here).
static int isVowel (tNode *this) {
char ch = this->ch;
return (ch == 'A') || (ch == 'E') || (ch == 'I')
|| (ch == 'O') || (ch == 'U');
}
Now this is the important bit, the bit that turns the single list into two distinct lists (one vowel, one consonant). Which list is which type depends on what the first entry in the list is.
What is basically does is to create a sub-list out of all the common nodes at the start of the list ("ST" in this case), another sub-list of the next non-matching type ("A"), and then starts processing the remaining nodes one by one, starting with "C".
As each subsequent node is examined, the pointers are adjusted to add it to either the first or second list (again, without actually creating new nodes). Once we reach the NULL at then end of the list, we then decide whether to append the second list to the first, or vice versa (vowels have to come first).
The code for all this pointer manipulation is shown below:
// Meat of the solution, reorganise the list.
static tNode *regroup (tNode *this) {
// No reorg on empty list.
if (this == NULL)
return this;
// Find first/last of type 1 (matches head), first of type 2.
tNode *firstTyp1 = this, *firstTyp2 = this, *lastTyp1 = this, *lastTyp2;
while ((firstTyp2 != NULL) && (isVowel (firstTyp1) == isVowel (firstTyp2 ))) {
lastTyp1 = firstTyp2;
firstTyp2 = firstTyp2->next;
}
// No type 2 means only one type, return list as is.
if (firstTyp2 == NULL)
return firstTyp1;
// Type 2 list has one entry, next node after that is for checking.
lastTyp2 = firstTyp2;
this = firstTyp2->next;
//dump (firstTyp1);
//dump (firstTyp2);
//putchar ('\n');
// Process nodes until list is exhausted.
while (this != NULL) {
// Adjust pointers to add to correct list.
if (isVowel (this) == isVowel (lastTyp1)) {
lastTyp2->next = this->next;
lastTyp1->next = this;
lastTyp1 = this;
} else {
lastTyp1->next = this->next;
lastTyp2->next = this;
lastTyp2 = this;
}
// Advance to next node.
this = this->next;
//dump (firstTyp1);
//dump (firstTyp2);
//putchar ('\n');
}
// Attach last of one list to first of the other,
// depending on which is the vowel list.
if (isVowel (firstTyp1)) {
lastTyp1->next = firstTyp2;
return firstTyp1;
}
lastTyp2->next = firstTyp1;
return firstTyp2;
}
And, finally, no complex program would be complete without a test harness of some description, so here it is, something to create and dump the list in its initial form, then reorganise it and dump the result:
int main (void) {
char *str = "STACKOVERFLOW";
tNode *list = NULL;
while (*str != '\0')
list = append (list, *(str++));
dump (list);
puts("");
list = regroup (list);
dump (list);
return 0;
}
Upon entering, compiling and running all that code, the results are as expected:
(09c03008)S -> (09c03018)T -> (09c03028)A -> (09c03038)C ->
(09c03048)K -> (09c03058)O -> (09c03068)V -> (09c03078)E ->
(09c03088)R -> (09c03098)F -> (09c030a8)L -> (09c030b8)O ->
(09c030c8)W
(09c03028)A -> (09c03058)O -> (09c03078)E -> (09c030b8)O ->
(09c03008)S -> (09c03018)T -> (09c03038)C -> (09c03048)K ->
(09c03068)V -> (09c03088)R -> (09c03098)F -> (09c030a8)L ->
(09c030c8)W
In case that's hard to read, I'll get rid of the pointers and just list the characters in order:
S -> T -> A -> C -> K -> O -> V -> E -> R -> F -> L -> O -> W
A -> O -> E -> O -> S -> T -> C -> K -> V -> R -> F -> L -> W