SAS Component Language 9.4 Reference

SAS Component Language 9.4 Reference
SAS Component
Language 9.4
®
Reference
Third Edition
SAS® Documentation
The correct bibliographic citation for this manual is as follows: SAS Institute Inc. 2014. SAS® Component Language 9.4: Reference, Third Edition.
Cary, NC: SAS Institute Inc.
SAS® Component Language 9.4: Reference, Third Edition
Copyright © 2014, SAS Institute Inc., Cary, NC, USA
All rights reserved. Produced in the United States of America.
For a hard-copy book: No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means,
electronic, mechanical, photocopying, or otherwise, without the prior written permission of the publisher, SAS Institute Inc.
For a web download or e-book: Your use of this publication shall be governed by the terms established by the vendor at the time you acquire this
publication.
The scanning, uploading, and distribution of this book via the Internet or any other means without the permission of the publisher is illegal and
punishable by law. Please purchase only authorized electronic editions and do not participate in or encourage electronic piracy of copyrighted
materials. Your support of others' rights is appreciated.
U.S. Government License Rights; Restricted Rights: The Software and its documentation is commercial computer software developed at private
expense and is provided with RESTRICTED RIGHTS to the United States Government. Use, duplication or disclosure of the Software by the
United States Government is subject to the license terms of this Agreement pursuant to, as applicable, FAR 12.212, DFAR 227.7202-1(a), DFAR
227.7202-3(a) and DFAR 227.7202-4 and, to the extent required under U.S. federal law, the minimum restricted rights as set out in FAR 52.227-19
(DEC 2007). If FAR 52.227-19 is applicable, this provision serves as notice under clause (c) thereof and no other notice is required to be affixed to
the Software or documentation. The Government's rights in Software and documentation shall be only those set forth in this Agreement.
SAS Institute Inc., SAS Campus Drive, Cary, North Carolina 27513-2414.
August 2014
SAS provides a complete selection of books and electronic products to help customers use SAS® software to its fullest potential. For more
information about our offerings, visit support.sas.com/bookstore or call 1-800-727-3228.
SAS® and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of SAS Institute Inc. in the USA and other
countries. ® indicates USA registration.
Other brand and product names are trademarks of their respective companies.
Contents
Recommended Reading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix
PART 1
SCL Fundamentals
1
Chapter 1 • Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Introduction to SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
SCL Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Entering SCL Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Compiling SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Testing SCL Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Debugging SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Saving SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Optimizing the Performance of SCL Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Using Other SAS Software Features in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . 7
SCL Compatibility Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Chapter 2 • The Structure of SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Introduction to SCL Program Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Using Labeled Sections in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Defining Classes in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Defining and Using Methods in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
USECLASS Blocks in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Defining Interfaces in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Using Macros in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Chapter 3 • SCL Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Introduction to SCL Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
SCL Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Names in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
SCL Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
SCL Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
SCL Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
SCL Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
SCL Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
SCL Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
SCL Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
SCL Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
SCL CALL Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Passing Arguments to SCL Functions and CALL Routines . . . . . . . . . . . . . . . . . . . . . . 37
Rules for SCL Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Chapter 4 • SCL Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Introduction to SCL Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Declaring Arrays in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Referencing Array Elements in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Initializing the Elements of a Static Array in SCL Programs . . . . . . . . . . . . . . . . . . . . . 43
Creating and Initializing Dynamic Arrays in SCL Programs . . . . . . . . . . . . . . . . . . . . . 45
vi Contents
Resizing Dynamic Arrays in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Using Array Functions with Dynamic Arrays in SCL Programs . . . . . . . . . . . . . . . . . . 46
Copying Elements from One Array to Another in SCL Programs . . . . . . . . . . . . . . . . . 47
Repeating an Action for Variables in an Array in SCL Programs . . . . . . . . . . . . . . . . . 49
Passing Dynamic Arrays to Methods in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . 49
Returning Arrays from Methods in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Deleting Dynamic Arrays in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Using Temporary Arrays to Conserve Memory in SCL Programs . . . . . . . . . . . . . . . . 51
Chapter 5 • SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Introduction to SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Creating Data Dynamically in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Identifying SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Creating New SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Initializing the Values in an SCL List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Manipulating SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Determining the Type of an SCL List Item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Passing SCL Lists as Arguments for Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Inserting and Replacing Items in SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Retrieving Values from SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Deleting Lists and List Items from SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Referencing SCL List Items by Index Number . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Accessing Items Relative to the End of an SCL List . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Index Errors in SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Implementing SCL Sublists and Nested Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Assigning Names to SCL List Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Using SCL Lists in Shared Data Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Using SCL Lists as Stacks and Queues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Assigning Attributes to SCL Lists and List Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Using SCL List File Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Debugging SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Chapter 6 • Controlling Program Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Introduction to SCL Program Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Using SCL DO Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Using SCL SELECT-WHEN/OTHERWISE Conditions . . . . . . . . . . . . . . . . . . . . . . . . 76
Using SCL IF-THEN/ELSE Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Using the SCL RETURN Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Branching to a Labeled Section (LINK) in SCL Programs . . . . . . . . . . . . . . . . . . . . . . 78
Branching to Another Entry (GOTO) in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . 79
Calling SCL Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Stopping Execution of the Current Section in SCL Programs . . . . . . . . . . . . . . . . . . . . 80
Executing Methods in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Using the SCL CONTROL Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Chapter 7 • Using SCL with Other SAS Software Products . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Introduction to Using SCL with SAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Using SAS DATA Step Features in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Submitting SAS Statements and SQL Statements in SCL Programs . . . . . . . . . . . . . . . 87
Submitting Statements Compared to Using SCL Features . . . . . . . . . . . . . . . . . . . . . . . 87
Designating Submit Blocks in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
How Submit Blocks Are Processed in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . 88
How Submitted Statements Are Formatted in SCL Programs . . . . . . . . . . . . . . . . . . . . 90
Modifying the Behavior of Submit Blocks in SCL Programs . . . . . . . . . . . . . . . . . . . . 90
Substituting Text in Submit Blocks in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Issuing Commands to Host Operating Systems from SCL Programs . . . . . . . . . . . . . . 94
Contents
vii
Using Macro Variables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
SCL and DATA Step Graphics Interface Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
BASE SAS Functions Used in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Differences Between SCL Functions and BASE Functions . . . . . . . . . . . . . . . . . . . . . 101
BASE SAS Statements Used in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
BASE SAS CALL Routines Used in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
PART 2
Developing Object-Oriented Applications
103
Chapter 8 • SAS Object-Oriented Programming Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Introduction to Object-Oriented Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Object-Oriented Programming and the SAS Component Object Model . . . . . . . . . . . 107
Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Accessing Object Attributes and Methods with Dot Notation . . . . . . . . . . . . . . . . . . . 132
Events and Event Handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Converting Version 6 Non-Visual Classes to SCOM Classes . . . . . . . . . . . . . . . . . . . 145
Chapter 9 • Example: Creating An Object-Oriented Application in SCL . . . . . . . . . . . . . . . . . . 151
Introduction to the SCL Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Simple Class Syntax in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Creating a Data Set Class in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Extending Classes in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Interfaces and Higher Levels of Abstraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Other Classes and Further Abstraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
The SCL USECLASS Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Using SCL Class Syntax with SAS/AF Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
PART 3
Application Considerations
169
Chapter 10 • Handling Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Introduction to SCL Exception Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Using the SCL programHalt Handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Handling SCL Exceptions with CATCH and THROW . . . . . . . . . . . . . . . . . . . . . . . . 173
Chapter 11 • Using SAS Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
Introduction to Using SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Accessing SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Assigning Librefs in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Opening SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
SAS Tables and the SCL Data Vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Reading SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
Controlling Access to SAS Table Rows in SCL Programs . . . . . . . . . . . . . . . . . . . . . 186
Changing the Sequence of Reading Rows in SCL Programs . . . . . . . . . . . . . . . . . . . . 188
Updating SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Closing SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Determining Attributes of SAS Tables and Columns in SCL Programs . . . . . . . . . . . 190
Performing Other SAS Table Operations in SCL Programs . . . . . . . . . . . . . . . . . . . . 191
Preserving the Integrity of Table Data in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . 192
viii Contents
Manipulating SAS Table Indexes in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Chapter 12 • Using External Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
Introduction to Using External Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . 196
Accessing External Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Assigning Filerefs in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Opening Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
File Data Buffers and SCL Data Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
Reading Values from External Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . 199
Modifying External Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
Closing Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
Changing the Sequence of Reading Records in SCL Programs . . . . . . . . . . . . . . . . . . 202
Other Ways SCL Interacts with External Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Reading and Modifying Files in the Same Directory with SCL . . . . . . . . . . . . . . . . . . 204
PART 4
Reference
207
Chapter 13 • SAS Component Language Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Chapter 14 • The SCL Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 743
Overview of SCL Debugger Features and Capabilities . . . . . . . . . . . . . . . . . . . . . . . . 744
Establishing the SCL Debugging Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745
Invoking the SCL Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746
Using the SCL Debugger Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746
Using SAS Macros with the SCL Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 747
SCL Debugger Commands by Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 748
Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 750
Chapter 15 • SAS System Return Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
Introduction to SAS System Return Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
Using SAS System Return Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
Testing for a Particular Error or Warning Condition . . . . . . . . . . . . . . . . . . . . . . . . . . 782
Mnemonics for SAS System Return Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783
PART 5
Appendices
793
Appendix 1 • Commands Used with the IMGCTRL, IMGOP and PICFILL Functions . . . . . . . . 795
Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796
Appendix 2 • Image File Types and Associated Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 835
File Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 835
Attributes for Reading Image Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 837
Attributes for Writing Image Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
Attributes for Reading Images from TWAIN Scanners . . . . . . . . . . . . . . . . . . . . . . . . 844
Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 847
ix
Recommended Reading
•
SAS Language Reference: Concepts
•
Base SAS Procedures Guide
•
SAS/ACCESS for Relational Databases: Reference
•
SAS/AF Procedure Guide
•
SAS/FSP Procedures Guide
•
Guide to SAS/AF Applications Development
•
SAS/GRAPH: Reference
For a complete list of SAS books, go to support.sas.com/bookstore. If you have
questions about which titles you need, please contact a SAS Book Sales Representative:
SAS Books
SAS Campus Drive
Cary, NC 27513-2414
Phone: 1-800-727-3228
Fax: 1-919-677-8166
E-mail: [email protected]
Web address: support.sas.com/bookstore
x Recommended Reading
1
Part 1
SCL Fundamentals
Chapter 1
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Chapter 2
The Structure of SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Chapter 3
SCL Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Chapter 4
SCL Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Chapter 5
SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Chapter 6
Controlling Program Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Chapter 7
Using SCL with Other SAS Software Products . . . . . . . . . . . . . . . . . . . . 83
2
3
Chapter 1
Introduction
Introduction to SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
SCL Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Entering SCL Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Compiling SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Compiling Your SCL Program Interactively . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Compiling Your SCL Program in Batch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
The SCL Data Vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Testing SCL Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Debugging SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Saving SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Optimizing the Performance of SCL Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Using Other SAS Software Features in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . 7
SCL Compatibility Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Introduction to SCL
SAS Component Language (SCL) is a programming language designed to facilitate the
development of interactive applications using the SAS System. For example, you can
use SCL with other SAS software to create data entry applications, to display tables and
menus, and to generate and submit SAS source code. SCL is the scripting language
behind SAS/AF, SAS/FSP, and SAS/EIS software. Applications developed using SCL
with SAS/AF software can be run by users who have only licensed Base SAS software.
Previous to Version 7, SAS Component Language was known as SAS Screen Control
Language.
SCL Elements
SAS Component Language has statements, functions, CALL routines, operators,
expressions, and variables—elements that are common to the Base SAS language and to
4
Chapter 1
• Introduction
many other programming languages. If you have experience writing DATA or PROC
steps in the Base SAS language, the basic elements of SCL are familiar to you. For
example, in SCL programs, you can use DO loops, IF-THEN/ELSE statements,
comparison operators such as EQ and LT, and SAS macros.
SCL provides additional statements, functions, and other features that make it easy to
create object-oriented, interactive applications. For example, SCL provides CLASS and
INTERFACE statements that enable you to define classes and interfaces to those classes.
You can use dot notation to access an object's attributes directly and to invoke methods
instead of using the SEND and NOTIFY routines.
“Introduction to SCL Program Structure” on page 9 describes the organization of an
SCL application.
“Introduction to SCL Fundamentals” on page 20 describes the basic elements of SCL
and the rules that you must follow to put these elements together in a program.
“Introduction to SCL Program Flow” on page 71 describes the statements and other
features that you can use to control the flow of your application.
Entering SCL Code
You can enter your SCL code in four ways:
•
In the SAS Explorer, select the catalog where you want to store your SCL code, and
select File ð New... ð SCL Program
•
Issue the BUILD command followed by the name of the entry that you want to edit:
BUILD libref.catalog.entry.SCL
•
In the Build window for the frame, select View ð Frame SCL
•
In the Build window for the program screen, select Tools ð Source Window
Compiling SCL Programs
Introduction
You must compile SCL programs before testing or executing an application. The SCL
compiler translates your SCL application into an intermediate form that can be executed
by the SCL interpreter. In the process of translating your application, the compiler
identifies any syntax errors that are present. You should correct these errors and compile
the code again until the program compiles without errors. If there are errors in the
program, then no intermediate code is produced, and running the entry produces a
message stating that the entry has no code.
The compiler produces a list of errors, warnings, and notes in the Log window. A
program that compiles with no errors or warnings produces a message like the following
in the message line of the Source window:
NOTE:
Code generated for SALES.FRAME. Code size=2649.
Compiling SCL Programs
5
Compiling Your SCL Program Interactively
You can compile frames, program screens, and SCL programs by issuing the COMPILE
command in the Build window or by selecting Compile from the pull-down menus. In
the Build window for frames or SCL programs, select Build ð Compile. In the Build
window for program screens, select Run ð Compile
If you change a frame or SCL entry and then compile, an interim version is saved and
compiled. However, if you then try to close the frame or SCL entry that you changed,
you will be prompted to save that entry even though you just compiled. You must save
the entry to retain your changes.
You can also compile FRAME, PROGRAM, and SCL entries from the SAS Explorer. If
your SCL code is associated with a frame or a program screen, then you must compile
the FRAME or PROGRAM entry in order for the associated code to be compiled
correctly. The SCL code is compiled when you compile the FRAME or PROGRAM
entry. If your SCL code is not associated with a FRAME or PROGRAM entry, then you
compile the SCL entry. To compile an entry from the Explorer, select the entry, then
select Compile from the pop-up menu.
If you compile a FRAME or PROGRAM entry that does not have any associated SCL
code, the SCL compiler displays an error message.
Compiling Your SCL Program in Batch
To compile your SCL application in batch, run PROC BUILD with the COMPILE
option:
PROC BUILD CATALOG=libref.catalog BATCH;
COMPILE <ENTRYTYPE=entry-type>;
RUN;
The default entry type is PROGRAM. If you do not specify an entry-type, then all
PROGRAM, FRAME, and SCL entries in the catalog are compiled. All PROGRAM,
FRAME, and SCL entries in an application must be compiled before the application can
be executed.
If you compile a frame in batch, and the compiler cannot find the associated SCL source,
the frame will not compile.
The SCL Data Vector
Compiling an SCL program opens a temporary storage area called the SCL data vector
(SDV). The SDV holds the values of all window, nonwindow, and system variables that
are used in the application.
The SDV is similar to the program data vector (PDV) that is created by base SAS
software when it compiles a DATA step. The program data vector holds the values of
the variables that are defined in the DATA step.
Areas in the SDV are created automatically for system variables as well as for window
variables for all controls in the application window, even if the variables are not used in
the SCL program. Figure 1.1 on page 6 shows the SDV for an application that uses
the window variables NAME, HEIGHT, AGE, and WEIGHT and the nonwindow
variables HFACTOR and WFACTOR.
6
Chapter 1
• Introduction
Figure 1.1
SCL Data Vector for a Typical Application
_CURROW_ _ERROR_
_MSG_
System
Variables
_STATUS_
NAME
HEIGHT
AGE
Window
Variables
WEIGHT
HFACTOR WFACTOR
Nonwindow
Variables
Testing SCL Applications
After an SCL program compiles successfully, you can test it. For catalog entries that use
the TESTAF, AF, or AFA command, you can issue the command from either the Source
window or the Display window. You must use the AF or AFA command if a program
contains SUBMIT statements, or if you are testing a FRAME entry that is in a library
accessed with SAS/SHARE software. It is recommended that you issue the SAVE
command before issuing the AF or AFA command.
SCL programs for FSEDIT and FSVIEW applications run when you return to the
FSEDIT or FSVIEW window.
Debugging SCL Programs
SCL includes an interactive debugger for monitoring the execution of SCL programs.
The debugger enables you to locate logical errors while a program is executing. To use
the debugger, issue the DEBUG ON command before compiling. Then either use the
TESTAF command or use the AF or AFA command with the DEBUG=YES option to
run the entry under the debugger. To deactivate the SCL debugger, issue the DEBUG
OFF command followed by the COMPILE command. For more information about the
SCL debugger, see Chapter 14, “The SCL Debugger,” on page 743.
Saving SCL Programs
After you create an SCL program, use the SAVE command to save it. You should also
use SAVE /ALL to save the entry before issuing a TESTAF command if the entry uses
CALL DISPLAY to call itself. Also be sure to save all other open entries before issuing
a TESTAF command so that CALL DISPLAY and method calls will execute the most
recent versions of your SAS/AF entries.
Optimizing the Performance of SCL Code
You can optimize the performance of SCL programs in your applications with the SCL
analysis tools.
SCL Compatibility Issues
7
The following table lists the available tools and provides information about when you
might want to use each tool.
Table 1.1
SCL Tools
Use the...
when you want to...
Coverage Analyzer
monitor an executing application and access a
report that shows which lines of SCL code are
not executed during testing.
List Diagnostic Utility
monitor an executing application and access
reports on the use of SCL lists, including any
lists that are left undeleted.
Performance Analyzer
monitor an executing application and identify
any bottlenecks in the application's SCL code.
Static Analyzer
access reports that detail SCL code
complexity; variable, function, method and
I/O usage; and error and warning messages.
To display a menu of the SCL analysis tools, enter sclprof at the command prompt.
For detailed information about using these tools, see the SAS/AF online Help.
Using Other SAS Software Features in SCL
Programs
SCL supports most of the features of the Base SAS language. Some Base SAS features
are directly supported by SCL. Other Base SAS features have equivalent features in
SCL, although there may be differences in functionality. For example, the IN operator in
SCL returns the index of the element if a match is found rather than a 1 (true).
The SCL language elements behave differently in SCL than in Base. The differences are
summarized in “Using SAS DATA Step Features in SCL Programs” on page 84.
Although SCL does not provide an equivalent for every command that is available under
your operating system, it does provide features that interact directly with SAS software
and with host operating systems. For example, you can use the SUBMIT statement to
access other features of SAS software, and you can use the SYSTEM function to issue
host operating system commands. SCL also supports the SAS macro facility. For more
information about these features, see “Introduction to Using SCL with SAS” on page
84.
SCL Compatibility Issues
The following are notable compatibility issues.
ACCESS routine
As of Version 8, the functionality of ACCESS is available through the CALL
BUILD routine. Both ACCESS and BUILD now open the Explorer window. Old
8
Chapter 1
• Introduction
programs that use ACCESS will still work, although the TYPE and MODE
parameters are not supported from the Explorer window. Using BUILD for new
programs is recommended because it provides additional functionality.
CALC routine
The CALL CALC routine is not supported beyond Version 6.12.
CARDS statement
As of Version 8, the DATA step statement DATALINES replaces the CARDS
statement.
CATALOG function
As of Version 8, the functionality of CATALOG is available through the CALL
BUILD routine. Like CATALOG, BUILD opens the Explorer window when a
catalog is specified as the first parameter. Old programs with the CATALOG
function will still run, although the SHOWTYPE and PMENU parameters are not
supported from the Explorer window. You should use BUILD for new programs.
CATLIST, DIRLIST, and FILELIST, and IVARLIST functions
Version 7 tables may contain mixed-case names. If any existing application relies on
one of these functions to return an uppercased name, you may need to modify the
application.
CATLIST, DIRLIST, FILELIST, and LIBLIST windows
As of Version 8, these windows have been replaced with host selector windows in
which the AUTOCLOSE option is ignored.
9
Chapter 2
The Structure of SCL Programs
Introduction to SCL Program Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Using Labeled Sections in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Reserved Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Window Variable Sections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Defining Classes in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Defining and Using Methods in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Defining Method Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Calling a Method That Is Stored in an SCL Entry . . . . . . . . . . . . . . . . . . . . . . . . . . 14
USECLASS Blocks in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Defining Interfaces in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Using Macros in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Introduction to SCL Program Structure
An SCL application consists of one or more SCL entries. These SCL entries can contain
the following types of modules:
•
labeled sections
•
CLASS blocks
•
METHOD blocks
•
USECLASS blocks
•
INTERFACE blocks
•
macros.
For example, an SCL program may consist of only one labeled section, or it may contain
two labeled sections, a METHOD block, and a couple of macros. A complex program
may contain several CLASS, METHOD, USECLASS, and INTERFACE blocks.
Some types of modules can be stored together in one SCL entry, but others cannot. One
SCL entry may contain any one of the following:
10
Chapter 2
•
The Structure of SCL Programs
•
one or more labeled sections and/or one or more macros
•
one CLASS block, which may also contain one or more METHOD blocks
•
one INTERFACE block
•
one or more USECLASS blocks, each of which may contain one or more METHOD
blocks
•
one or more METHOD blocks (that are not contained within a CLASS or
USECLASS block).
In strictly object-oriented applications, METHOD blocks are contained within CLASS
or USECLASS blocks. If your application is not a strictly object-oriented application,
you can save METHOD blocks by themselves in SCL entries.
Object-oriented applications use CLASS, METHOD, USECLASS, and INTERFACE
blocks extensively. For information about designing and implementing object-oriented
applications see Guide to SAS/AF Applications Development in addition to the
information contained in this documentation.
Using Labeled Sections in SCL Programs
Introduction
SCL programs execute in phases, such as the initialization phase and the termination
phase. During each phase, control of the entry can pass to a different segment of an SCL
program. The segments of the program are identified by labels; that is, the SCL program
is divided into labeled sections.
Labeled sections are program segments that are designed to be called only within the
program in which they are defined. Labeled sections begin with a label and end with a
RETURN statement. A label may be one of the reserved labels such as INIT or MAIN; it
may correspond to a field name, window-variable name, or object name in your
application; or it may simply identify a module that is called repetitively, such as a
module that sorts data.
Labeled sections are a good solution when you are working within one SCL program
because they can help divide the program into smaller, simpler pieces.
For example, the following SCL program contains an INIT section that is executed
before the application window is displayed; two sections that correspond to window
variables, NAME and ADDRESS; and a MAIN section that is executed each time the
user updates a field in the window.
init:
...some SCL statements...
return;
name:
...some SCL statements...
return;
address:
...some SCL statements...
return;
main:
Using Labeled Sections in SCL Programs
11
...some SCL statements...
return;
Reserved Labels
There are five reserved labels:
FSEINIT
An FSEINIT section, which is valid in FSEDIT and FSBROWSE applications only,
contains any statements that are needed to initialize the application. These statements
are executed one time only when the user invokes the FSEDIT or FSBROWSE
procedure and before the first row is displayed.
INIT
The INIT section is executed before the application window is displayed to the user.
Typically, you use the INIT section to initialize variables, to import values through
macro variables, to open tables, and to define initial messages to display when the
window is opened. In FSEDIT and FSBROWSE applications, as well as Data Table
and Data Form controls, the INIT section is executed before each SAS table row is
displayed.
MAIN
The MAIN section is executed each time the user modifies a field in the window and
presses ENTER.
TERM
The TERM section is executed when the user issues the END command. You might
use the TERM section to close tables, to export values of macro variables, and to
construct and submit statements for execution. In FSEDIT applications, Data Table
controls, and Data Form controls, the TERM section is executed after each SAS table
row is displayed, provided that the MAIN section has been executed for the row.
FSETERM
The FSETERM section is valid in FSEDIT applications only. This section executes
once after the user issues the END command and terminates the FSEDIT procedure.
In FSVIEW applications, you write individual formulas consisting of one or more lines
of SCL code for each computed variable, rather than complete SCL programs. These
formulas are stored in FORMULA entries. The FSVIEW procedure automatically adds a
label before the formula and a RETURN statement after the formula. The label is the
same as the name of the variable whose value you are calculating.
An SCL program for FSEDIT or FSBROWSE applications must contain at least one of
the following reserved labels: INIT, MAIN, or TERM. If a program does not include at
least one of these three reserved labels, the procedure never passes control to your SCL
program. If a program does not contain all three of these reserved labels, you get one or
more warning messages when you compile the program.
The FSEINIT and FSETERM labels are optional. The compiler does not issue any
warnings if these labels are not present.
Neither SCL programs for FRAME entries nor programs in SCL entries that contain
method block definitions require any reserved sections.
For more information about the FSVIEW, FSEDIT, and FSBROWSE procedures,
seeSAS/FSP Procedures Guide. For more information about FRAME applications, see
Guide to SAS/AF Applications Development.
12
Chapter 2
•
The Structure of SCL Programs
Window Variable Sections
Introduction
SCL provides a special type of labeled section, called a window variable section, that
automatically executes when a user takes an action in a particular control or field. For
example, window variable sections might be used to verify values that users enter in
controls or fields. An SCL program can include labeled sections for any number of
window variables.
The sequence for executing window variable sections is determined by the physical
position of the window element. Window variable sections execute sequentially for each
window element, from left to right and from top to bottom. A window variable section
must be labeled with the name of the associated window variable. For more information
about window variables, see Guide to SAS/AF Applications Development.
Correcting Errors in Window Variables
To correct an error in a window variable, you can allow users to correct the error in the
window, or you can include a CONTROL ERROR statement along with statements in
the window variable section that make a correction, as shown in the following example:
INIT:
control error;
return;
Name:
if error(Name) then do;
erroroff Name;
Name=default-value-assigned-elsewhere;
_msg_=
'Value was invalid and has been reset.';
end;
return;
Using a window variable section in this manner reduces overhead because the program's
MAIN section executes only after the window variable sections for all modified window
variables have executed correctly.
If a program also uses CONTROL ERROR, CONTROL ALWAYS, or CONTROL
ALLCMDS, then the MAIN section executes after the window variable sections even if
an error has been introduced. For more information about the CONTROL statement, see
“CONTROL” on page 274.
Defining Classes in SCL Programs
Classes define data and the operations that you can perform on that data. You define
classes with the CLASS statement. For example, the following code defines a class,
Simple, that defines an attribute named total and implements a method named
addNums:
Example Code 2.1 Defining a Class with SCL
class Simple;
Defining and Using Methods in SCL Programs
13
public num total;
addNums: public method n1:num n2:num return=num;
total=n1+n2;
return(total);
endmethod;
endclass;
The CLASS statement does not implement the methods. It only declares them. For
example:
class Simple;
public num total;
addNums: public method n1:num n2:num return=num
/ (scl=work.a.simMeth.scl');
endclass;
The code to implement the method is contained in work.a.simMeth.scl (see
“USECLASS Blocks in SCL Programs” on page 14).
For more information about defining and using classes, see
•
“Introduction to Object-Oriented Programming” on page 106
•
“Introduction to the SCL Tutorial” on page 151
•
“CLASS” on page 249
Defining and Using Methods in SCL Programs
Introduction
Methods define operations that you can perform on data. Methods are defined with the
METHOD statement. Methods can be implemented in CLASS blocks or in USECLASS
blocks. In addition, if you are not designing a strictly object-oriented application, they
can be stored in separate SCL entries.
Storing method implementations in SCL entries enables you to write methods that
perform operations that are common to or shared by other applications. You can call the
methods from any SAS/AF application.
For more information about defining and using methods in CLASS and USECLASS
blocks, see
•
“Introduction to Object-Oriented Programming” on page 106
•
“Introduction to the SCL Tutorial” on page 151
Defining Method Blocks
To define a method, use the METHOD statement. For example, the METHOD statement
above, in Example Code 2.1 on page 12, defines the public method addNums, which
takes two numeric parameters, adds them, and returns the total.
14
Chapter 2
•
The Structure of SCL Programs
Note: Do not include window-specific statements or functions (for example, the
PROTECT and CURSOR statements and the FIELD and MODIFIED functions) in
method blocks that are stored in independent SCL entries. SCL entries that contain
window-specific statements or functions will not compile independently. They must
be compiled in conjunction with the associated FRAME entry.
When you want to pass parameters between an SCL program and a method block, you
use the same principles as when you are passing parameters between a CALL DISPLAY
statement and an ENTRY statement. Unless the REST=, ARGLIST=, or OPTIONAL=
option is used in the METHOD statement, the parameter list for the METHOD statement
and the argument list for the associated ENTRY statement must agree in the following
respects:
•
The number of parameters passed by the METHOD statement must equal the
number of arguments received by the ENTRY statement.
•
The position of each parameter in the METHOD statement must be the same as the
position of the corresponding argument in the ENTRY statement.
•
Each parameter in the METHOD statement and its corresponding argument in the
ENTRY statement must have the same data type.
The parameters and arguments do not have to agree in name. For more information, see
“METHOD (define)” on page 535 and “ENTRY” on page 346.
Calling a Method That Is Stored in an SCL Entry
If the method module is stored in a PROGRAM entry or SCREEN entry, then you must
use a LINK or GOTO statement to call it. Although parameters cannot be passed with
LINK or GOTO statements, you can reference global values in those statements.
If the module is an SCL entry, then call the method module with a CALL METHOD
routine. The CALL METHOD routine enables you to pass parameters to the method. For
example, a program that needs to validate an amount can call the AMOUNT method,
which is stored in METHDLIB.METHODS.VALIDATE.SCL:
call method('methdlib.methods.validate.scl',
'amount',amount,controlid);
After the method module performs its operations, it can return modified values to the
calling routine.
If the method module is stored in the SCL entry that is associated with the FRAME
entry, then you must compile the SCL entry as a separate entity from the FRAME entry
in addition to compiling the FRAME entry.
For more information about the CALL METHOD routine, see “METHOD (execute)” on
page 533.
USECLASS Blocks in SCL Programs
USECLASS blocks contain method blocks. A USECLASS block binds the methods that
are implemented within it to a class definition. This binding enables you to use the
attributes and methods of the class within the methods that are implemented in your
USECLASS block. However, your USECLASS block does not have to implement all of
the methods defined in the class.
Using Macros in SCL Programs
15
For example, the USECLASS block for the class defined in “Defining Classes in SCL
Programs” on page 12 would be stored in work.a.simMeth.scl and would contain
the following code:
useclass simple.class;
addNums: public method n1:num n2:num return=num;
total=n1+n2;
return(total);
endmethod;
enduseclass;
Using USECLASS blocks to separate the class definition from the method
implementations enables multiple programmers to work on method implementations
simultaneously.
For more information, see
•
“Introduction to Object-Oriented Programming” on page 106
•
“The SCL USECLASS Statement” on page 164
•
“USECLASS” on page 706
Defining Interfaces in SCL Programs
Interfaces are groups of method declarations that enable classes to possess a common set
of methods even if the classes are not related hierarchically. Interfaces are especially
useful when you have several unrelated classes that perform a similar set of actions.
These actions can be declared as methods in an interface, and each associated class can
provide its own implementation for each of the methods. In this way, interfaces provide
a form of multiple inheritance.
For more information about defining and using interfaces, see
•
“Introduction to Object-Oriented Programming” on page 106
•
“Introduction to the SCL Tutorial” on page 151
•
“INTERFACE” on page 475
Using Macros in SCL Programs
Introduction
You can use the SAS macro facility to define macros and macro variables for your SCL
program. That is, you can use SAS macros and SAS macro variables that have been
defined elsewhere in the SAS session or in autocall libraries. You can then pass
parameters between macros and the rest of your program. In addition, macros can be
used by more than one program. However, macros can be more complicated to maintain
than the original program segment because of the symbols and quoting that are required.
If a macro is used by more than one program, you must keep track of all the programs
that use the macro so that you can recompile all of them each time the macro is updated.
Because SCL is compiled (rather than interpreted like the SAS language), each SCL
16
Chapter 2
•
The Structure of SCL Programs
program that calls a macro must be recompiled whenever that macro is updated in order
to update the program with the new macro code.
Macros and macro variables in SCL programs are resolved when you compile the SCL
program, not when a user executes the application. However, you can use the SYMGET
and SYMGETN functions to retrieve the value of a macro variable or to store a value in
a macro variable at execution time, and you can use the SYMPUT and SYMPUTN
functions to create a macro variable at execution time. For more information, see “Using
Macro Variables in SCL Programs” on page 94.
Note: Macros and macro variables within submit blocks are not resolved when you
compile the SCL program. Instead, they are passed with the rest of the submit block
to SAS software when the block is submitted. For more information about submit
blocks, see “Submitting SAS Statements and SQL Statements in SCL Programs” on
page 87.
Note: Using macros does not reduce the size of the compiled SCL code. Program
statements that are generated by a macro are added to the compiled code as if those
lines existed at that location in the program.
Example
The following code defines two macros, VALAMNT and RATEAMNT, that validate
values entered in two text entry controls, Amount and Rate.
%macro valamnt;
if amount.text < 0 or amount.text > 500 then do;
amount._erroron();
_msg_='Amount must be between $0 and $500.';
stop;
end;
else amount._erroroff();
%mend;
%macro rateamnt;
if rate.text < 0 or rate.text > 1 then do;
rate._erroron();
_msg_='Rate must be between 0 and 1.';
stop;
end;
else rate._erroroff();
%mend;
To use these two macros, create a frame that contains two Text Entry controls, Amount
and Rate. Set the dataType attribute for each control to Numeric. Use the following code
in the frame SCL:
INIT:
control error;
amount.text=0;
rate.text=.5;
return;
MAIN:
payment=amount*rate;
put payment=;
return;
AMOUNT:
Using Macros in SCL Programs
%valamnt
return;
RATE:
%rateamnt
return;
17
18
Chapter 2
•
The Structure of SCL Programs
19
Chapter 3
SCL Fundamentals
Introduction to SCL Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
SCL Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Declaring Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Numeric (NUM) Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Character (CHAR) Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Names in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
SCL Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
SCL Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Window Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Nonwindow Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
System Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
SCL Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Numeric Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Character Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Numeric-to-Character Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
SCL Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Arithmetic Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Comparison Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Logical (Boolean) Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
SCL Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Boolean Numeric Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Using Functions in Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
SCL Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Executable and Declarative Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
The Assignment Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
SCL Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
SCL Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
SCL CALL Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
20
Chapter 3
•
SCL Fundamentals
Passing Arguments to SCL Functions and CALL Routines . . . . . . . . . . . . . . . . . . . 37
Input, Output, and Update Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Rules for SCL Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Introduction to SCL Fundamentals
Like any language, SAS Component Language has its own vocabulary and syntax. An
SCL program consists of one or more SCL statements, which can include keywords,
expressions, constants, and operators.
To be more consistent with database management terminology, SCL now uses the terms
table, row, and column in place of data set, observation, and variable. However, you may
still encounter the old terms in some SAS products and documentation.
SCL Data Types
Introduction
SCL has the following data types:
•
NUM
•
CHAR
•
LIST
•
generic OBJECT
•
specific object (CLASS or INTRFACE).
Declaring Data Types
You can use the DECLARE statement for declaring any type of SCL variable. You can
use the LENGTH statement for declaring numeric and character variables.
You can also declare data types when you use the ENTRY and METHOD statements. In
these statements, you must specify a colon before a named data type; with an unnamed
data type, (for example, $), the colon is optional. For example:
ENTRY: name :$20
location $20
zipcode :num
mybutton :mylib.mycat.button.class
return=char;
For details, see
•
“DECLARE” on page 304
•
“LENGTH (declaration)” on page 501
•
“ENTRY” on page 346
•
“METHOD (define)” on page 535
SCL Data Types
21
Numeric (NUM) Variables
Numeric variables contain numbers and are stored as doubles. They are declared with
the keyword NUM.
/* declare a numeric variable AGE
declare num age;
*/
/* declare the numeric variables AGE and YEARS*/
declare num age, years;
/* declare numeric variables X and Y.
/* Initialize X to 1 and Y to 20 plus the
/* value of X.
declare num x, y=20+x;
*/
*/
*/
Character (CHAR) Variables
Character variables can contain up to 32,767 characters and are declared with the
keyword CHAR. A variable that is declared as CHAR without a specified length is
assigned a default length of 200.
/* declare a character variable NAME and
/* assign the value ABC to it
declare char name='abc';
*/
*/
/* declare a character variable NAME
/* with a length of 20
declare char(20) name;
*/
*/
The STRING data type is an alias of the CHAR data type.
Lists
SCL lists are ordered collections of data. Lists are dynamic; they grow and shrink to
accommodate the number or size of the items that you store in them. Lists can contain
items of different data types.
To declare an SCL list, use the keyword LIST. The following example declares the list
MYLIST:
declare list mylist;
The function that creates the list (for example, MAKELIST) assigns the identifier for the
list to the variable, as shown below.
declare list mylist;
...more SCL statements...
mylist=makelist();
Note: To maintain compatibility with previous releases, the SCL compiler does not
generate error messages if a list is not declared or if it is declared as a numeric
variable. However, it is recommended that you declare lists so that the compiler can
identify errors. A list must be declared as type List when it is passed to a method that
requires an argument of type List. See “Overloading and List, Object, and Numeric
Types” on page 123.
22
Chapter 3
•
SCL Fundamentals
For information about using lists, see “Introduction to SCL Lists” on page 54.
Objects
Introduction
Objects can be declared in either of two ways:
•
as a specific object of type CLASS or INTRFACE. When an object is declared with
the name of the class, the compiler can validate attributes and methods for the object
and can return error messages if incorrect attributes or methods are used.
•
as a generic object of type Object. The specific object class that is associated with
the generic object cannot be resolved until run time. The compiler reserves space in
the SAS Data Vector (SDV) for the object, but it cannot validate attributes or
methods for the object, because it does not know the names of classes. Instead, this
validation is deferred until program execution. Consequently, you should use the
OBJECT keyword to declare an object only when necessary, so that you can obtain
optimal run-time performance.
You can use dot notation for accessing attributes and methods for both specific objects
and generic objects.
Note: If you want to use dot notation to access the attributes or methods of a Version 6
widget, then you need to declare its widget ID of OBJECT type, and you must obtain
its widget ID with the _getWidget method. For example, Text is a Version 6 text
entry widget. To access its methods or attributes with dot notation, you should use
code that looks like this:
dcl object obj;
/* dcl sashelp.fsp.efield.class obj; */
call notify ( 'Text', '_getWidget', obj );
obj.backgroundColor = 'blue';
See “Accessing Object Attributes and Methods with Dot Notation” on page 132 for
more information.
Specific Objects (CLASS and INTERFACE)
The following example declares an object named DataHolder as an instance of the
Collection class, which is provided with SAS software:
declare sashelp.fsp.collection.class DataHolder;
When you declare a class, you can also use the IMPORT statement to reference the class
and then use an abbreviated form of the class name in the DECLARE statement. For
example:
import sashelp.fsp.collection.class;
declare collection DataHolder;
Generic OBJECTs
In the following example, MyObject is recognized by the compiler as an object, but the
compiler has no information about the type of class instance that the object will actually
be:
declare object MyObject;
Names in SCL
23
Specifying the Object Type at Run Time
The following example declares an object named PgmObj2 and then specifies one
condition under which PgmObj2 will be a collection object and another condition under
which PgmObj2 will be an object that is created from a class named Foo. The _NEW_
operator creates the object.
declare object PgmObj2,
num
x;
if x=1 then
PgmObj2=_new_ sashelp.fsp.collection.class;
else
PgmObj2=_new_ sashelp.fsp.foo.class;
As described above, you can use the IMPORT statement to reference a class definition
and then use an abbreviated class name when you create the class.
import sashelp.fsp.collection.class;
import sashelp.fsp.foo.class;
declare object PgmObj2,
num
x;
if x=1 then
PgmObj2=_new_ collection();
end;
else
PgmObj2=_new_ foo();
Any errors that result from using incorrect methods or attributes for PgmObj2 and Foo
will cause the program to halt.
Names in SCL
In SCL, the rules for names are
1. Librefs and filerefs can have a maximum length of 8 characters. Other names —
including names of SCL variables, arrays, SCL lists, SAS tables, views, indexes,
catalogs, catalog entries, macros, and macro variables — can be 32 characters long.
2. The first character must be a letter (A, B, C, . . . , Z) or an underscore (_).
Subsequent characters can be letters, numeric digits (0, 1, . . . , 9), or underscores.
3. Names are stored in the case in which they are entered, which can be lower case,
mixed case, or upper case.
4. Names cannot contain blanks.
5. SCL honors the names that are reserved by SAS software for automatic variables,
lists of variables, SAS tables, and librefs. Thus, you cannot use these names in your
SCL programs.
a. When creating variables, do not use the names of special SAS automatic
variables (for example, _N_ and _ERROR_) nor the names of lists of variables
(for example, _CHARACTER_, _NUMERIC_, and _ALL_).
b. Do not use any of the following names as a libref:
•
SASCAT
•
SASHELP
•
SASMSG
24
Chapter 3
•
SCL Fundamentals
•
SASUSER
•
USER
•
WORK
Use LIBRARY only as the libref to point to a SAS data library containing a
FORMATS catalog that was created with PROC FORMAT.
c. Do not assign any of the following names to a SAS table:
•
_NULL_
•
_DATA_
•
_LAST_
Just as SCL recognizes keywords from position and context, it also recognizes names in
the same way. If SCL sees a word that meets the requirements for a user-supplied SAS
name and that is not used in a syntax that defines it as anything else, it interprets the
word as a variable name.
SCL Keywords
An SCL keyword is a word or symbol in an SCL statement that defines the statement
type to SAS software. Keywords are a fixed part of the SCL, and their form and meaning
are also fixed. Generally, keywords define the function or CALL routine that you are
using in an SCL program statement. For example, OPEN is the keyword in
table-id=OPEN('MYLIB.HOUSES');
SCL Variables
Introduction
SCL variables have most of the same attributes as variables in the Base SAS language:
•
name
•
data type
•
length.
However, SCL variables do not have labels.
SCL provides three categories of variables:
window variables
are linked to a control (widget) or field in a window. They pass values between an
SCL program and the associated window.
nonwindow variables
are defined in an SCL program. They hold temporary values that users do not need to
see.
system variables
are provided by SCL. They hold information about the status of an application.
SCL Variables
25
As in the Base SAS language, you can group variables into arrays to make it easier to
apply the same process to all the variables in a group. Arrays in SCL are described in
“Introduction to SCL Arrays” on page 41.
Window Variables
Introduction
Most SCL programs are associated with a window for interacting with users. An SCL
program for a window has variables that are associated with the controls and fields in the
window. These variables are called window variables, and they are the means by which
users and SCL programs communicate with each other. You can use these variables in
the SCL program without explicitly declaring them.
Name
The name of a window variable is the same as the name that is assigned to the control or
field. The SCL program for the window cannot change that name.
Data Type
A window variable also has a data type, which can be character, numeric, or an object
data type. The type is determined by the value of the Type attribute, which is displayed
in the Properties window (for a control) or in the Attributes window (for a field). For
more information about data types that are used in SAS/AF applications, see the
SAS/AF online Help and Guide to SAS/AF Applications Development.
Length
Lengths of window variables are determined as follows:
•
Numeric and object variables are stored internally as doubles.
•
Character variables have a maximum length that equals the width of the
corresponding field in the application window. For example, if a field occupies 20
columns in the window, then the maximum length of the associated window variable
is 20.
SCL programs can use methods to alter the lengths of window variables for some
FRAME entry controls. Otherwise, you cannot alter the length of a window variable in
an SCL program. Specifying a length for a window variable in a DECLARE or
LENGTH statement produces an error message when you compile the program.
Nonwindow Variables
Introduction
SCL programs can define and use variables that do not have associated controls or fields
in the window. These variables are called nonwindow variables, and they are used to
hold values that users do not need to see. SCL programs that do not have an associated
window use only nonwindow variables. Nonwindow variables are also referred to as
program variables. Because nonwindow variables are used only within an SCL program,
they have no informat or format.
26
Chapter 3
•
SCL Fundamentals
Name
The name of a nonwindow variable is determined by the first assignment statement that
uses the variable, unless the variable is explicitly defined with a DECLARE or
LENGTH statement. Names of nonwindow variables can be up to 32 characters long.
Data Type
Nonwindow variables are numeric unless they are explicitly declared as a different data
type.
Length
Lengths of nonwindow variables are determined as follows:
•
Numeric and object variables are stored as doubles.
•
Character variables have a default length of 200. However, you can use the
DECLARE statement to change the length from a minimum length of 1 to a
maximum of 32K.
You can use the DECLARE or LENGTH statement to specify a different maximum
length for nonwindow character variables. This can significantly reduce memory
requirements if your program uses many nonwindow variables.
Scope
The scope of a variable determines when a value can be assigned to it and when its value
is available for use. In general, variables in an SCL program have program scope. That
is, their scope is local to the program. They are available for use within the SCL program
but not to other parts of SAS software. When the program finishes, the variables no
longer exist, so their values are no longer available.
SCL provides a feature for defining variables as local to a DO or SELECT block. To
define a variable with this type of scope, use a DECLARE statement inside a DO or
SELECT block. Any variable that you declare in this way exists only for the duration of
that DO or SELECT block, and its value is available only during that time. For example,
the following program uses two variables named SECOND. One variable is numeric by
virtue of the first assignment statement. The other is a character variable that is local to
the DO block. After the DO block ends, only the numeric SECOND variable is
available.
INIT:
first=10;
second=5;
put 'Before the DO block: ' first= second=;
do;
/* Declare variable THIRD and new
/* variable SECOND, which is local to
/* the DO block and is CHAR data type
declare char(3) second third;
second='Jan';
third ='Mar';
/* FIRST is available because
*/
/* it comes from parent scope. */
put 'Inside the DO block: '
first= second= third=;
end;
/* THIRD is not available because */
/* it ended when the DO block ended. */
put 'After the DO block: '
*/
*/
*/
SCL Variables
27
first= second= third=;
return;
The example produces the following output:
Before the DO block: first=10 second=5
Inside the DO block: first=10 second=Jan third=Mar
After the DO block: first=10 second=5 third=.
Although program variables are available only while an SCL program is running, SCL
provides features for passing variables to other programs and also for receiving returned
values. For more information, see “ENTRY” on page 346 and “METHOD (execute)” on
page 533.
You can also use global macro variables to make variables available outside the SCL
program. See “Using Macro Variables in SCL Programs” on page 94 for details.
System Variables
System variables are created automatically when an SCL program compiles. These
variables communicate information between an SCL program and an application, and
you can use them in programs. System variables can be Character, Numeric, or Object
data type variables. The Object data type facilitates compile-time checking for SCL
programs that use dot notation to invoke methods and to access attributes for objects.
Although the system variables _CFRAME_, _FRAME_, and _SELF_ are designated as
object variables in Version 8 and later, applications that were built with earlier releases
and that use these variables will continue to work.
Do not declare the _SELF_, _FRAME_, _CFRAME_, _METHOD_, or _EVENT_
system variables inside a CLASS or USECLASS block. SCL automatically sets these
values when it is running methods that are defined in CLASS or USECLASS blocks.
Redefining any of these system variables can introduce unexpected behavior.
With the exceptions of _EVENT_, _METHOD_, and _VALUE_, you can simply
reference a system variable in an SCL program without explicitly declaring it.
_BLANK_
reports whether a window variable contains a value or sets a variable value to blank.
Type: Character
_CFRAME_
contains the identifier of the FRAME entry that is currently executing, when a
control is executing a method. Otherwise, it stores the identifier of the FRAME entry
that is executing.
Type: Object
_CURCOL_
contains the value of the first column on the left in an extended table object in a
FRAME entry. It is used to control horizontal scrolling.
Type: Numeric
_CURROW_
contains the number of the current row in an extended table.
Type: Numeric
_ERROR_
contains a code for the application's error status.
Type: Numeric
28
Chapter 3
•
SCL Fundamentals
_EVENT_
returns the type of event that occurred on a control. It is useful only during a _select
method. At other times, it may not exist as an attribute or it is blank. _EVENT_ can
have one of the following values:
”
modification or selection
C
command
D
double click
P
pop-up menu request
S
selection or single click.
_EVENT_ must be explicitly declared in an SCL program. For example: declare
char(1) _event_;
Type: Character.
_FRAME_
contains the identifier of the FRAME entry that contains a control, when the object is
a FRAME entry control. Otherwise, it contains the identifier of the FRAME entry
that is currently executing. You can use this variable to send methods to a FRAME
entry from a control's method. For example, a control method can send a _refresh
method to the FRAME entry, causing the FRAME entry to refresh its display.
Type: Object
_METHOD_
contains the name of the method that is currently executing.
_METHOD_ must be explicitly declared in an SCL program. In the declaration
statement, specify the maximum length for the name of a method. For example:
declare char(40) _method_;
Type: Character.
_MSG_
assigns text to display on the message line, or contains the text to be displayed on the
window's message line the next time the window is refreshed.
Type: Character
_SELF_
contains the identifier of the object that is currently executing a method.
Type: Object
_STATUS_
contains a code for the status of program execution. You can check for the value of
_STATUS_, and you can also set its value.
Type: Character
_VALUE_
contains the value of a control.
When _VALUE_ contains the value of a character control, it must be explicitly
declared in an SCL program. In the declaration statement, specify the maximum
SCL Constants
29
length for a character window control. For example: declare char(80)
_value_;
Type: Character or Numeric.
SCL Constants
Introduction
In SCL, a constant (or literal) is a fixed value that can be either a number or a character
string. Constants can be used in many SCL statements, including assignment and IFTHEN statements. They can also be used as values for certain options.
Numeric Constants
A numeric constant is a number that appears in a SAS statement, and it can be presented
in the following forms:
•
standard syntax, in which numeric constants are expressed as integers, can be
specified with or without a plus or minus sign, and can include decimal places.
•
scientific (E) syntax, in which the number that precedes the E is multiplied by the
power of ten indicated by the number that follows the E.
•
hexadecimal syntax, in which a numeric hex constant starts with a numeric digit
(usually 0), can be followed by more hexadecimal digits, and ends with the letter X.
The constant can contain up to 16 hexadecimal digits (0 to 9, A to F).
•
special SAS date and time values, in which the date or time is enclosed in single or
double quotation marks, followed by a D (date), T (time), or DT (datetime) to
indicate the type of value (for example, '15jan99'd).
Character Constants
A character constant can consist of 1 to 32,767 characters and must be enclosed in
quotation marks. Character constants can be represented in the following forms:
•
hexadecimal form, in which a string of an even number of hex characters is enclosed
in single or double quotation marks, followed immediately by an X, as in this
example:
'534153'x
•
bit form, in which a string of 0s, 1s, and periods is surrounded by quotation marks
and is immediately followed by a B. Zero tests whether a bit is off, 1 tests whether a
bit is on, and a period ignores a bit. Commas and blanks can be inserted in the bit
mask for readability without affecting its meaning.
In the following example, if the third bit of A (counting from the left) is on, and the
fifth through eighth bits are off, then the comparison is true and the expression
results in 1. Otherwise, the comparison is false and the expression results in 0.
if a='..1.0000'b then do;
Bit constants cannot be used as literals in assignment statements. For example, the
following statement is not valid:
30
Chapter 3
•
SCL Fundamentals
x='0101'b;
/* incorrect */
If a character constant includes a single quotation mark, then either write the quotation
mark as two consecutive single quotation marks or surround the entire value with double
quotation marks, as shown in the following examples:
possession='Your”s';
company="Your's and Mine"
company="Your""s and Mine"
To use a null character value as an argument to a function in SCL, either use '' (without
a space) or use a blank value with ' ' (with a space).
Numeric-to-Character Conversion
If a value is inconsistent with the variable's data type, SCL attempts to convert the value
to the expected type. SCL automatically converts character variables to numeric
variables and numeric variables to character variables, according to the following rules:
•
•
A character variable is converted to numeric when the character variable is used
•
with an operator that requires numeric operands (for example, the plus sign)
•
with a comparison operator (for example, the equal sign) to compare a character
variable and a numeric variable
•
on the right side of an assignment statement, when a numeric variable is on the
left side.
A numeric variable is converted to character when the numeric variable is used
•
with an operator that requires a character value (for example, the concatenation
operator)
•
on the right side of an assignment statement, when a character variable is on the
left side.
When a variable is converted automatically, a message in the LOG window warns you
that the conversion took place. If a conversion from character to numeric produces
invalid numeric values, then a missing value is assigned to the result, an error message
appears in the LOG window, and the value of the automatic variable _ERROR_ is set to
1.
SCL Operators
Introduction
Operators are symbols that request an arithmetic calculation, a comparison, or a logical
operation. SCL includes the same operators that are provided in the Base SAS language.
The only restrictions on operators in SCL are for the minimum and maximum value
operators. For these SAS operators, you must use the operator symbols (> < and < >,
respectively) rather than the mnemonic equivalents (MIN and MAX, respectively).
SCL Operators
Arithmetic Operators
The arithmetic operators, which designate that an arithmetic calculation is performed,
are shown here:
Table 3.1
Arithmetic Operators
Symbol
Definition
+
addition
/
division
**
exponentiation
*
multiplication
-
subtraction
Comparison Operators
Introduction
Comparison operators propose a relationship between two quantities and ask whether
that relationship is true. Comparison operators can be expressed as symbols or written
with letters. An operator that is written with letters, such as EQ for =, is called a
mnemonic operator. The symbols for comparison operators and their mnemonic
equivalents are shown in the following table:
Table 3.2
Comparison Operators
Mnemonic
Symbol
Equivalent
Definition
=
EQ
equal to
^= *
NE
not equal to
¬= *
NE
not equal to
>
GT
greater than
<
LT
less than
>= **
GE
greater than or equal to
<= **
LE
less than or equal to
<>
maximum
31
32
Chapter 3
• SCL Fundamentals
Mnemonic
Symbol
Equivalent
Definition
><
minimum
||
concatenation
IN
equal to one item in a list
* * The symbol that you use for NE depends on your keyboard.
** ** The symbols =< and => are also accepted for compatibility with previous releases of SAS.
Colon Modifier
You can add a colon (:) modifier after any operator to compare only a specified prefix of
a character string. For example, the following code produces the message pen found,
because the string pen occurs at the beginning (as a prefix) of pencil:
var='pen';
if var =: 'pencil'
then put var 'found';
else
put var 'not found';
The following code produces the message phone not found because phone occurs
at the end (as a suffix) of telephone:
var='phone';
if var =: 'telephone';
then put var 'found';
else put var 'not found';
The code produces these messages:
pen found
phone not found
IN Operator
The IN operator compares a value produced by an expression on the left side of the
operator to a list of values on the right. For example:
if age in (16, 21, 25);
The IN operator returns 0 if the value on the left does not match a value in the list. The
result is 1 if the value on the left matches a value in the list. In the case of arrays, the IN
operator returns the index of the element if it finds a match.
The form of the comparison is
expression IN (value-1<, . . . ,value-n>)
The elements of the comparison are
expression
can be any valid SAS expression, but it is usually a variable name when used with
the IN operator.
value
must be a SAS constant. Value can be an array of constants.
Suppose you have the following program section:
SCL Operators
33
init:
declare a[5] = (2 4 6 8 10);
b = 6;
if b in a then put 'B is in array A';
c=b in a;
put c=;
return;
This code produces the following output:
B is in array A
c=3
Logical (Boolean) Operators
Introduction
Logical operators (also called Boolean operators) are usually used in expressions to link
sequences of comparisons. The logical operators are shown in the following table:
Table 3.3
Logical Operators
Mnemonic
Symbol
Equivalent
Definition
&
AND
AND comparison
|
OR
OR comparison
¬*
NOT
NOT comparison
^*
NOT
NOT comparison
~*
NOT
NOT comparison
* * The symbol that you use for NOT depends on your keyboard.
AND Operator
If both conditions compared by an AND operator are true, then the result of the AND
operation is true. Two comparisons with a common variable linked by AND can be
condensed with an implied AND. For example, the following two subsetting IF
statements produce the same result:
if 16<=age and age<=65;
if 16<=age<=65;
OR Operator
If either condition compared by an OR operator is true, then the result of the OR
operation is true.
Be careful when using the OR operator with a series of comparisons (in an IF, SELECT,
or WHERE statement, for example). Remember that only one comparison in a series of
OR comparisons needs to be true in order to make a condition true. Also, any nonzero,
34
Chapter 3
•
SCL Fundamentals
nonmissing constant is always evaluated as true. Therefore, the following subsetting IF
statement is always true:
if x=1 or 2;
Although X=1 may be either true or false, the 2 is evaluated as nonzero and nonmissing,
so the entire expression is true. In the following statement, however, the condition is not
necessarily true, because either comparison can evaluate as true or false:
if x=1 or x=2;
You can also use the IN operator with a series of comparisons. The following statements
are equivalent:
if x in (2, 4, 6);
if x=2 or x=4 or x=6;
NOT Operator
Putting NOT in front of a quantity whose value is false makes that condition true. That
is, negating a false statement makes the statement true. Putting NOT in front of a
quantity whose value is missing is also true. Putting NOT in front of a quantity that has a
nonzero, nonmissing value produces a false condition. That is, the result of negating a
true statement is false.
SCL Expressions
Introduction
An SCL expression can be a sequence of operands and operators forming a set of
instructions that are performed to produce a result value, or it can be a single variable
name, constant, or function. Operands can be variable names or constants, and they can
be numeric, character, or both. Operators can be symbols that request a comparison, a
logical operation, or an arithmetic calculation. Operators can also be SAS functions and
grouping parentheses.
Expressions are used for calculating and assigning new values, for conditional
processing, and for transforming variables. These examples show SAS expressions:
•
3
•
x
•
age<100
•
(abc)/2
•
min(2,-3,1)
SCL expressions can resolve to numeric, character, or Boolean values. In addition, a
numeric expression that contains no logical operators can serve as a Boolean expression.
Boolean Numeric Expressions
In SCL programs, any numeric value other than 0 or missing is true, whereas a value of
0 or missing is false. Therefore, a numeric variable or expression can stand alone in a
condition. If the value is a number other than 0 or missing, then the condition is true; if
the value is 0 or missing, then the condition is false.
SCL Statements 35
A numeric expression can be simply a numeric constant, as follows:
if 5 then do;
The numeric value returned by a function is also a valid numeric expression:
if index(address,'Avenue') then do;
Using Functions in Expressions
You can use functions almost any place in an SCL program statement where you can use
variable names or literal values. For example, the following example shows a way to
perform an operation (in this case, the FETCH function) and take an action, based on the
value of the return code from the function:
rc=fetch(dsid);
/* The return code -1 means the
/* end of the file was reached.
if (rc=-1) then
do;
...SCL statements to handle the
end-of-file condition...
end;
*/
*/
To eliminate the variable for the return code, you can use the function directly in the IF
statement's expression, as shown in the following example:
if (fetch(dsid)=-1) then
do;
...SCL statements to handle the
end-of-file condition...
end;
In this case, the FETCH function is executed, and then the IF expression evaluates the
return code to determine whether to perform the conditional action.
As long as you do not need the value of the function's return code for any other
processing, the latter form is more efficient because it eliminates the unnecessary
variable assignment.
SCL Statements
Introduction
SCL provides all of the program control statements of the Base SAS language. However,
many Base SAS language statements that relate to the creation and manipulation of SAS
tables and external files are absent in SCL. In their place, SCL provides an extensive set
of language elements for manipulating SAS tables and external files. These elements are
described in “Introduction to Using SAS Tables in SCL Programs” on page 180 and in
“Introduction to Using External Files in SCL Programs” on page 196.
SCL also provides CLASS and INTERFACE statements, which enable you to design
and build true object-oriented applications. CLASS statements enable you to define
classes from which you can create new objects. The INTERFACE statement enables you
to define how applications can communicate with these objects.
36
Chapter 3
•
SCL Fundamentals
Executable and Declarative Statements
As in the Base SAS language, SCL statements are either executable or declarative.
executable statements
are compiled into intermediate code and result in some action when the SCL
program is executed. (Examples of executable statements are the CURSOR, IFTHEN/ELSE, and assignment statements.)
declarative statements
provide information to the SCL compiler but do not result in executable code unless
initial values are assigned to the declared variables. (Examples of declarative
statements are the DECLARE, LENGTH, and ARRAY statements.)
You can place declarative statements anywhere in an SCL program, but they typically
appear at the beginning of the program before the first labeled section.
CAUTION:
Do not place executable statements outside the program modules. Executable
statements outside a program module (labeled section, class definition file, method
implementation file, and so on) are never executed. See “Introduction to SCL
Program Structure” on page 9 for more information about program modules.
The Assignment Statement
The assignment statement in SCL works like the assignment statement in Base SAS
except:
•
You can specify an array name (without the subscript) in the left side of the
assignment statement. See “Using Assignment Statements” on page 47 and
“Returning Arrays from Methods in SCL Programs” on page 50 for more
information.
•
You can use the assignment statement to initialize the values of an SCL list. See
“Initializing the Values in an SCL List” on page 57 for more information.
SCL Comments
You can include comments anywhere in your SCL programs. Comments provide
information to the programmer, but they are ignored by the compiler, and they produce
no executable code.
SCL allows the following two forms of comments:
•
/* comment */
/* sort the data set and */
/* then do something else */
sysrc=sort(dsid,'year month');
•
* comment ;
* sort the data set and ;
* then do something else ;
sysrc=sort(dsid,'year month');
Passing Arguments to SCL Functions and CALL Routines
37
SCL Functions
Like the functions in the Base SAS language, each SCL function returns a value that is
based on one or more arguments that are supplied with the function. Most of the special
features of SCL are implemented as functions. In addition, SCL provides all of the
functions of the Base SAS language except for the DIF and LAG functions. (The DIF
and LAG functions require a queue of previously processed rows that only the DATA
step maintains.)
SCL functions can be divided into the following groups according to the type of
information they return:
•
functions that return a value representing the result of a manipulation of the
argument values. For example, the MLENGTH function returns the maximum length
of a variable.
•
functions that perform an action and return a value indicating the success or failure
of that action. For these functions, the value that the function returns is called a
return code. For example, the LIBNAME function returns the value 0 if it
successfully assigns a libref to a SAS data library or directory. If the function cannot
assign the libref, it returns a nonzero value that reports the failure of the operation.
The SYSMSG function returns the text of the error message that is associated with
the return code.
Note: Some functions use a return code value of 0 to indicate that the requested
operation was successful, whereas other functions use a return code of 0 to
indicate that the operation failed.
SCL CALL Routines
Like functions, CALL routines perform actions, based on the values of arguments that
are supplied with the routine name. However, unlike functions, CALL routines do not
return values. Many halt the program if the call is unsuccessful. Use CALL routines to
implement features that do not require return codes.
SCL has a variety of CALL routines of its own. It also supports all of the CALL routines
that are provided by the Base SAS language.
Passing Arguments to SCL Functions and CALL
Routines
Additional restrictions apply to the values that you pass as arguments to SCL functions
and CALL routines. Some SCL functions and CALL routines accept only names of
variables as arguments, but for most arguments you can specify either a literal value or
the name of a variable that contains the desired value. For some functions, passing
missing values for certain arguments causes the SCL program to stop executing and to
display an error message. Restrictions on argument values are described in the each
function and routine entry.
38
Chapter 3
•
SCL Fundamentals
Input, Output, and Update Parameters
Parameters to functions and methods can be one of three types:
input
The value of the parameter is passed into the function, but even if the function
modifies the value, it cannot pass the new value out to the calling function.
output
Output parameters are used to return a value from a function.
update
Update parameters can be used to pass a value into a function, and the function can
modify its value and return the new value out to the calling function.
Note: If you use dot notation to specify a parameter to a method, then the parameter is
treated as an update parameter if the method does not have a signature or if the
object is declared as a generic object. SCL executes the _setAttributeValue method
for all update parameters, which could cause unwanted effects. See “What Happens
When Attribute Values Are Set or Queried” on page 135 for complete information.
If you do not use dot notation to pass parameters, then all parameters are input
parameters except for those listed in the following table.
Table 3.4
Functions With Update Parameters
Function Name
Update Parameters
DELNITEM
index
DIALOG
all parameters other than entry
DISPLAY
all parameters other than entry
FGET
cval
FILEDIALOG
filename
FILLIST
description
LVARLEVEL
n-level
CALL METHOD
all parameters except entry and label
NAMEDIVIDE
all parameters except name
NOTIFY
all parameters except control-name and method-name
RGBDM
RGB-color
SAVEENTRYDIALOG
description
SEND
all parameters except object-id and method-name
Rules for SCL Statements
Function Name
Update Parameters
SETNITEMC
index
SETNITEML
index
SETNITEMN
index
SETNITEMO
index
SUPER
all parameters except object-id and method-name
VARLEVEL
n-level
VARSTAT
varlist-2
39
Note: The argument parameter of the DATA step SUBSTR (left of =) function is also
an update parameter.
For all methods that you define with the METHOD statement, all parameters are
assumed to be update parameters unless either you specify input or output when you
define the method or you invoke the method with SEND, NOTIFY, SUPER, or CALL
METHOD. If you invoke the method with SEND, NOTIFY, SUPER, or CALL
METHOD, then the first two parameters are assumed to be input parameters.
Rules for SCL Statements
The statements that you use in SCL programs must conform to the following rules:
•
You must end each SCL program statement with a semicolon.
•
You can place any number of SCL program statements on a single line as long as
you separate the individual statements with semicolons. If you plan to use the SCL
debugger, it is helpful to begin each statement on a separate line.
•
You can continue an SCL program statement from one line to the next as long as no
keyword is split.
•
You can begin SCL program statements in any column.
•
You must separate words in SCL program statements with blanks or with special
characters such as the equal sign (=) or another operator.
•
You must place arguments for SCL functions and CALL routines within parentheses.
•
If a function or CALL routine takes more than one argument, you must separate the
arguments with commas.
•
Character arguments that are literal values must be enclosed in either single or
double quotation marks (for example, 'Y' or “N”).
•
Numeric arguments cannot be enclosed in quotation marks.
40
Chapter 3
•
SCL Fundamentals
41
Chapter 4
SCL Arrays
Introduction to SCL Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Declaring Arrays in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Referencing Array Elements in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Grouping Variables That Have Sequential Names . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Initializing the Elements of a Static Array in SCL Programs . . . . . . . . . . . . . . . . . 43
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Assigning the Same Value to Multiple Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Initializing Static Multidimensional Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Creating and Initializing Dynamic Arrays in SCL Programs . . . . . . . . . . . . . . . . . 45
Resizing Dynamic Arrays in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Explicitly Resizing An Array With REDIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Using Array Functions with Dynamic Arrays in SCL Programs . . . . . . . . . . . . . . 46
Copying Elements from One Array to Another in SCL Programs . . . . . . . . . . . . . 47
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Using Assignment Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Using The COPYARRAY Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Repeating an Action for Variables in an Array in SCL Programs . . . . . . . . . . . . . 49
Passing Dynamic Arrays to Methods in SCL Programs . . . . . . . . . . . . . . . . . . . . . . 49
Returning Arrays from Methods in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . 50
Deleting Dynamic Arrays in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Using Temporary Arrays to Conserve Memory in SCL Programs . . . . . . . . . . . . . 51
Introduction to SCL Arrays
SCL supports two types of arrays: static and dynamic. The size of a static array is set
when you declare the array and cannot be changed at runtime. With dynamic arrays, you
do not specify a size when you declare the array, but you can use any one of several
different SCL functions to control the size of the array. With a dynamic array, you can
create an array of a specified size and resize the array explicitly as needed in your
program. You can also specify that the array is implicitly growable.
42
Chapter 4
•
SCL Arrays
The differences between ARRAY statement execution in SCL and ARRAY statement
execution in the DATA step are described in “Introduction to Using SCL with SAS” on
page 84.
Declaring Arrays in SCL Programs
You can use the DECLARE statement to declare static or dynamic arrays. Arrays that
are declared with the DECLARE statement are all temporary arrays. That is, they default
to the _TEMPORARY_ option. (See “Using Temporary Arrays to Conserve Memory in
SCL Programs” on page 51 for more information.) For example, the following
statement declares an array named MONTH that contains five character variables that
are each up to three characters in length:
declare char(3) month[5];
To declare a dynamic array, you must specify an asterisk (*) for the array dimensions:
declare char students[*];
This statement declares a one-dimensional array of type character. The DECLARE
statement does not set the array bounds or create any elements. Dynamic arrays are only
accessible within the scope in which they are declared.
You can use the ARRAY statement to declare indirect or non-temporary arrays. You can
declare only static arrays with the ARRAY statement. You can declare temporary arrays
by specifying the _TEMPORARY argument in the ARRAY statement. For example:
array month[5] $;
The ARRAY statement (but not the DECLARE statement) enables you to assign names
to individual array elements. For example, the following statement assigns the names
JAN, FEB, MAR, APR, and MAY to the five elements in the MONTH array:
array month[5] $ jan feb mar apr may;
You can use these names to refer to the array elements in your SCL program.
In contrast to the ARRAY statement, you cannot use the DECLARE statement to assign
names to individual array elements. The following DECLARE statement declares an
array named MONTH plus five more character variables named JAN, FEB, MAR, APR,
and MAY:
declare char month[5] jan feb mar apr may;
Referencing Array Elements in SCL Programs
Introduction
To reference array elements, you can use the form array-name[position], where position
is the index position of the variable in the array. This form of array reference is called
subscripting. Subscripting is the only way to refer to array elements that were declared
with the DECLARE statement. For example, FACTOR[4] is the only way to reference
the fourth element of array FACTOR if it is created with the statement
declare num Factor[5];
Initializing the Elements of a Static Array in SCL Programs
43
This DECLARE statement also produces variables FACTOR[1] through FACTOR[5].
Because you must use the DECLARE statement to declare dynamic arrays, the only way
to reference the elements of a dynamic array is with subscripting. However, you cannot
reference the elements of a dynamic array until you have created the array. See
“Creating and Initializing Dynamic Arrays in SCL Programs” on page 45 for more
information.
You can also use subscripting to refer to elements of an array that is declared with the
ARRAY statement. For example, you can use MONTH[1] and MONTH[4] to refer to
the first and fourth elements of an array that is declared with the following statement:
array month[5] $;
If the array is declared with an ARRAY statement that does not assign individual names
to the array elements (as shown in this example), then you can also refer to these array
elements as MONTH1 and MONTH4.
If the ARRAY statement assigns names to the individual array elements, then you can
also use those names to refer to the array elements. For example, if you declare your
array with the following statement, then you can refer to the elements in the array using
the names JAN, FEB, and MAR:
array month[3] $ jan feb mar;
Grouping Variables That Have Sequential Names
If an application program or window has a series of variables whose names end in
sequential numbers (for example, SCORE1, SCORE2, SCORE3, and so on), then you
can use an array to group these variables. For example, the following ARRAY statement
groups the variables SCORE1, SCORE2, SCORE3, and SCORE4 into the array
SCORE:
array score[4];
Note: If the variables do not already exist as window variables, then SCL defines new,
nonwindow, numeric variables with those names.
Grouping the variables into an array is useful when your program needs to apply the
same operations to all of the variables. See “Repeating an Action for Variables in an
Array in SCL Programs” on page 49 for more information.
Initializing the Elements of a Static Array in SCL
Programs
Introduction
By default, all elements in a numeric array are initialized to numeric missing values if
the array elements did not previously exist.
You can define initial values for the elements of a static array by listing the initial values
in parentheses following the list of element names in the DECLARE or ARRAY
statements. Commas are optional between variable values. For example, the following
ARRAY statement creates a two-item array named COUNT, assigns the value 1 to the
first element, and assigns the value 2 to the second element:
array count[2] (1 2);
44
Chapter 4
•
SCL Arrays
You can also initialize array elements with the DECLARE statement. For example, the
following program declares an array named MONTH, which contains five elements that
can each contain three characters, and it assigns initial values to the array elements:
declare char(3) month[5]=('jan' 'feb' 'mar'
'apr' 'may');
INIT:
put month;
return;
The example produces the following output:
month[1]
month[2]
month[3]
month[4]
month[5]
=
=
=
=
=
'jan'
'feb'
'mar'
'apr'
'may'
Assigning the Same Value to Multiple Elements
You can use repetition factors to initialize static arrays. Repetition factors specify how
many times the values are assigned in the array. They have the following form:
5 * (2 3 4)
In this example, 5 is the repetition factor and (2 3 4) is the list of initial values for the
array elements. If the list consists of only a single item, then you can omit the
parentheses.
For example, the following ARRAY and DECLARE statements both use repetition
factors to initialize the values of the array REPEAT:
array repeat[17] (0,3*1,4*(2,3,4),0);
declare num repeat[17]=(0,3*1,4*(2,3,4),0);
This example repeats the value 1 three times and the sequence 2, 3, 4 four times. The
following values are assigned to the elements of the array REPEAT:
0, 1, 1, 1, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, 0
Initializing Static Multidimensional Arrays
To initialize a static multidimensional array, use the ARRAY or DECLARE statement to
list values for the first row of the array, followed by values for the second row, and so
on. The following examples both initialize a two-dimensional array named COUNT with
two rows and three columns:
array count[2,3] (1 2 3 4 5 6);
dcl num count[2,3]=(1 2 3 4 5 6);
Table 4.1
Values of the Elements of the COUNT Array
Column 1
Column 2
Column 3
Row 1
1
2
3
Row 2
4
5
6
Resizing Dynamic Arrays in SCL Programs
45
For more information about arrays, see “ARRAY” on page 220 and “DECLARE” on
page 304.
Creating and Initializing Dynamic Arrays in SCL
Programs
Dynamic arrays can be created and initialized in five ways:
•
with the COPYARRAY function. See “Using The COPYARRAY Function” on page
47 for more information.
•
using simple assignment statements that copy the values of one array into another
array. For more information, see “Using Assignment Statements” on page 47.
•
by a method that returns an array. See “Returning Arrays from Methods in SCL
Programs” on page 50 for more information.
•
with the REDIM function. See “Resizing Dynamic Arrays in SCL Programs” on
page 45 for more information.
•
with the MAKEARRAY function.
After you have declared a dynamic array, you can create the array with the
MAKEARRAY function. The MAKEARRAY function creates an array of the given
size with all elements in the array initialized to missing for numerics or blank for
characters. The number of dimensions must be the same as what was specified in the
DECLARE statement. The low bound for all dynamic arrays is 1, and the high bound is
determined at runtime by the values that you specify with the MAKEARRAY (or
REDIM) function. For example, the following statements create a one-dimensional
dynamic array named STUDENTS that has three elements and initializes these array
elements to Mary, Johnny, and Bobby:
declare char students[*];
students = MAKEARRAY(3);
students[1] = 'Mary';
students[2] = 'Johnny';
students[3] = 'Bobby';
put students;
The low bound for STUDENTS is 1, and the high bound 3. The output for this example
is
students[1] = 'Mary'
students[2] = 'Johnny'
students[3] = 'Bobby'
Resizing Dynamic Arrays in SCL Programs
Introduction
You can use the REDIM function to explicitly change the high bound of any dimension
of a dynamic array at runtime. You can use the REDIMOPT function to mark an array as
implicitly growable.
46
Chapter 4
•
SCL Arrays
Explicitly Resizing An Array With REDIM
With REDIM, you cannot change the number of dimensions or type of the array, only
the bounds. The REDIM function will also preserve the data in the array unless you
resize the array to a smaller size. If you reduce the size of an array, you will lose the data
in the eliminated elements.
For example, suppose that you have declared and initialized the STUDENTS array as
shown in “Creating and Initializing Dynamic Arrays in SCL Programs” on page 45. To
add another student, you must resize the array. The following statements increase the
high bound by 1 element, add the new variable STUDENTS[4], and initialize this new
element to Alice.
declare num rc;
rc = REDIM(students, DIM(students) + 1);
students[DIM(students)] = 'Alice';
put students;
All of the existing data is preserved. The low bound for the array STUDENTS is 1, and
the new high bound is 4. The output for this example would be:
students[1]
students[2]
students[3]
students[4]
=
=
=
=
'Mary'
'Johnny'
'Bobby'
'Alice'
You can also use the REDIM function to create and initialize an array that has been
declared but not yet created by other means. For example, the following statements
declare, create, and initialize an array of five elements to numeric missing values:
dcl num rc;
dcl num a[*];
rc = redim(a,5);
There is no limit to the number of times that you can resize an array.
Note: You can use the MAKEARRAY function to resize an array, but all the data will
be lost. The MAKEARRAY function will reinitialize the elements to missing
numeric values or to blank character values.
Using Array Functions with Dynamic Arrays in
SCL Programs
You can use dynamic arrays with the other existing array functions (DIM, HBOUND,
LBOUND) as long as the array has been created with MAKEARRAY or REDIM. If
your program references a dynamic array before it has been created, a program halt will
occur. If you pass a dynamic array to a method by reference (that is, as an input
parameter), you cannot resize the array using MAKEARRAY, REDIM, or DELARRAY
within the method.
Copying Elements from One Array to Another in SCL Programs
47
Copying Elements from One Array to Another in
SCL Programs
Introduction
There are two ways to copy an array:
•
using an assignment statement. When assigning the values of one array to another
array, the two arrays must have the same size.
•
using the COPYARRAY function. When using the COPYARRAY function, the
arrays do not have to be the same size.
Using Assignment Statements
You can assign values to an array from another array in an assignment statement. For
example, the following code copies the values of array A into array B:
declare num a[3] = (1 3 5);
declare num b[3];
b = a;
put b;
These statements produce the following output:
b[1] = 1
b[2] = 3
b[3] = 5
When you use the assignment statement to copy an array, the two arrays must have the
same type, dimensions, and size; otherwise, an error condition will occur.
You can use an assignment statement to create and initialize a dynamic array that has
been declared but not yet created. If you specify a newly declared dynamic array as the
array to which values are to be assigned, then SCL will create the dynamic array and
copy the values of the existing array into the new array.
For example, the following statements create dynamic array B to the same size as A and
then copies the values of array A into dynamic array B.
declare num a[3] = (1 3 5);
declare num b[*];
b = a;
put b;
These statements produce the following output:
b[1] = 1
b[2] = 3
b[3] = 5
Using The COPYARRAY Function
You can also use the COPYARRAY function to copy elements from one array to
another. By default, the COPYARRAY function produces the same result as the
48
Chapter 4
•
SCL Arrays
assignment statement and requires that the arrays be of the same type, dimension, and
size. For example, the following statements copy the array A into arrays B and C:
declare num a[3] = (1 3 5);
declare num b[3] c[3];
rc = COPYARRAY(a,b);
put b;
c = a;
put c;
The output for this code would be:
b[1]
b[2]
b[3]
c[1]
c[2]
c[3]
=
=
=
=
=
=
1
3
5
1
3
5
However, with the COPYARRAY function, you can copy an array to an array of a
different size if you set the IGNORESIZE parameter to Y in the call to COPYARRAY:
rc = COPYARRAY(array1,array2,'Y');
The type and dimensions of the arrays must still match. For example, the following
statements will copy array A, which has three elements, into array B, which has five
elements.
declare num a[3] = (1 3 5);
declare num b[5];
rc = COPYARRAY(a,b,'Y');
put b;
This code produces the following output:
b[1]
b[2]
b[3]
b[4]
b[5]
=
=
=
=
=
1
3
5
.
.
The COPYARRAY can also be used to create dynamic arrays, just as you can create
them using assignment statements. For example, the following statements create and
initialize dynamic array B:
declare num a[3] = (1 3 5);
declare num b[*];
rc = COPYARRAY(a,b);
put b;
The output for this code would be:
b[1] = 1
b[2] = 3
b[3] = 5
Note: When you use the COPYARRAY function to create a new dynamic array, it is
good practice to delete the newly created array using the DELARRAY function.
However, if you do not delete the array with the DELARRAY function, SCL will
delete the array at the end of the routine like all other dynamic arrays. See “Deleting
Dynamic Arrays in SCL Programs” on page 51 for more information.
Passing Dynamic Arrays to Methods in SCL Programs
49
Repeating an Action for Variables in an Array in
SCL Programs
To perform an action on variables in an array, you can use an iterative DO statement,
using the index variable for the array subscript. A DO block is especially convenient
when arrays contain many elements. For example, you could use a program like the
following to sum the values of the array variables and to display the total in the SUM
field:
array month[5] jan feb mar apr may (1,2,3,4,5);
INIT:
do i=1 to 5;
sum+month[i];
end;
put month;
put sum=;
return;
The example produces the following output:
month[1]
month[2]
month[3]
month[4]
month[5]
sum=15
=
=
=
=
=
1
2
3
4
5
The preceding DO block has the same effect as any one of the following assignment
statements:
sum1=jan+feb+mar+apr+may;
sum2=sum(of month[*]);
sum3=sum(of jan--may);
put sum1= sum2= sum3= ;
This example produces the following output:
sum1=15 sum2=15 sum3=15
Passing Dynamic Arrays to Methods in SCL
Programs
Passing a dynamic array to a method is no different than passing a static array, but the
dynamic array must have been created by MAKEARRAY, REDIM, COPYARRAY, or
an assignment statement. If the dynamic array is not created before the method call, then
an error condition will occur.
Dynamic arrays can be resized via a method if the method's parameter is a reference
array and an output parameter. See “ARRAY” on page 220 for more information on
reference arrays.
Suppose you have defined the resizeDynamicArray method as follows:
50
Chapter 4
•
SCL Arrays
resizeDynamicArray:method parm1[*]:O:num;
declare num rc = redim(parm1, 5);
endmethod;
The parameter PARM1 is output parameter and a reference array. When you call this
method, it will resize the dynamic array passed to it into an array with a low bound 1 and
a high bound of 5. In the following code, resizeDynamicArray resizes an array with 3
elements into an array with 5 elements:
declare num a[*] = MAKEARRAY(3);
object.resizeDynamicArray(a);
put a;
The output for this code would be:
a[1]
a[2]
a[3]
a[4]
a[5]
=
=
=
=
=
.
.
.
.
.
Because PARM1 is a reference array, it is using the same memory as the dynamic array
A.
You can now resize the array using MAKEARRAY, REDIM, COPYARRAY,
DELARRAY, or an assignment statement.
Returning Arrays from Methods in SCL Programs
Arrays can also be assigned values from a method that returns an array. The array to
which values are being assigned must have the same type, dimensions, and size as the
array returned from the method. Otherwise, an error condition will occur.
Suppose you define the getArrayValues method as follows:
getArrayValues:method return=num(*);
declare num a[3] = (1 3 5);
return a;
endmethod;
To assign the values that are returned by getArrayValues to an array, you could use the
following code:
declare num b[3];
b = object.getArrayValues();
put b;
The output for this example is
b[1] = 1
b[2] = 3
b[3] = 5
Dynamic arrays (that have not yet been created by other means) can be created when an
array is returned from a method call. If your program returns values into a dynamic array
that has been declared but not yet created, SCL will first create the new dynamic array,
then copy the returned values into the new array. For example, the following code
creates dynamic array B with the same size as the returned array and copies the values of
the returned array into B.
Using Temporary Arrays to Conserve Memory in SCL Programs
51
declare num b[*];
b = getArrayValues();
put b;
The output of these statements is
b[1] = 1
b[2] = 3
b[3] = 5
Deleting Dynamic Arrays in SCL Programs
The DELARRAY function is used to delete a dynamic array that has been created using
the MAKEARRAY or REDIM. The array's contents cannot be accessed after the array is
deleted. If you do not delete the created dynamic array using DELARRAY, the array
will be automatically deleted when exiting the routine.
Using Temporary Arrays to Conserve Memory in
SCL Programs
If you want to use an array in an SCL program but do not need to refer to array elements
by name, then you can add the _TEMPORARY_ argument to your ARRAY statement:
array total[4] _temporary_;
When you use the _TEMPORARY_ argument, you must use subscripting to refer to the
array elements. For example, you must use TOTAL[2] to refer to the second element in
the array TOTAL, defined above. You cannot use the variable name TOTAL2 as an
alternative reference for the array element TOTAL[2]. Using the _TEMPORARY_
argument conserves memory. By default, SCL allocates memory for both the name of
the array and the names of the individual array elements. However, when you use the
_TEMPORARY_ argument, SCL allocates memory only for the array name. For large
arrays, this can result in significant memory savings.
Note: Do not use the _TEMPORARY_ option if you plan to use the SET routine to read
values from a SAS table directly into array elements. You must use the GETVARN
or GETVARC function to read values from a SAS table into the elements of a
temporary array.
52
Chapter 4
•
SCL Arrays
53
Chapter 5
SCL Lists
Introduction to SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Creating Data Dynamically in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Identifying SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Creating New SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Example: Creating an SCL List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Initializing the Values in an SCL List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Manipulating SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Determining the Type of an SCL List Item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Passing SCL Lists as Arguments for Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Inserting and Replacing Items in SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Retrieving Values from SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Deleting Lists and List Items from SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Referencing SCL List Items by Index Number . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Accessing Items Relative to the End of an SCL List . . . . . . . . . . . . . . . . . . . . . . . . . 61
Index Errors in SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Implementing SCL Sublists and Nested Structures . . . . . . . . . . . . . . . . . . . . . . . . . 61
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Limitless Levels of Nesting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Simulating Multidimensional Arrays with Nested Lists . . . . . . . . . . . . . . . . . . . . . 63
Saving Nested Lists to SCL Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Assigning Names to SCL List Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Indexing a Named Item by its Position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Determining or Replacing an Item's Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Finding an Occurrence of a Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Specifying Where the Search for an Item Starts . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Using SCL Lists in Shared Data Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Local Data Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Global Data Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Using SCL Lists as Stacks and Queues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Using a List as a Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
54
Chapter 5
•
SCL Lists
Using a List as a Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Assigning Attributes to SCL Lists and List Items . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Using SCL List File Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Debugging SCL Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Introduction to SCL Lists
SCL supports data structures and functions for manipulating data in SCL lists. SCL lists,
like arrays, are ordered collections of data. However, lists are more flexible than arrays
in many ways. For example, SCL lists are dynamic. Therefore, a program can create a
list only when and if it is needed. Lists grow and shrink to accommodate the number of
items or the size of items that you assign to them. Also, an SCL list can contain items of
differing data types.
Creating Data Dynamically in SCL
SCL lists are dynamic rather than static. That is, SCL programs create these lists at run
time. This means that list sizes are computed at run time rather than before the list is
created. Further, unlike arrays, which have a fixed size, a list's length can grow or shrink
to accommodate the amount of data you want to maintain.
SCL lists can contain items of mixed types, whereas SCL arrays are fixed in type.
(Depending on its declaration, an array contains either numeric data or character data,
but not both). One item in an SCL list can be a number and the next item can be a
character string, while a third might be another list. Further, you have the freedom to
replace a numeric value with a character value in a list, and vice versa. Although you can
make lists that are of fixed type, you have the freedom to allow multiple types in the
same list.
Note: Character values that are stored in SCL lists can be up to 32,766 characters per
item.
Identifying SCL Lists
You access lists with a list identifier, a unique value assigned to each list that you create.
You must store the list identifier in an SCL variable and then reference that variable in
each operation that you perform on the list. All the SCL functions that manipulate lists
use the list identifier as an argument.
Note: Assigning a list identifier to another variable does not copy the list. The two
variables simply refer to the same list. To copy the contents of a list to an existing or
new list, use the COPYLIST function.
Creating New SCL Lists
55
Creating New SCL Lists
Introduction
SCL lists can be declared using the LIST data type, which is a reference type that stores
the identifier assigned when you create the list. You assign the LIST type with the
DECLARE statement. For example:
declare list carlist;
After you declare a list, you actually create it with the MAKELIST or MAKENLIST
function. You can then insert numbers, characters, other lists, or objects into the list with
the INSERTN, INSERTC, INSERTL, or INSERTO function, respectively. You can also
specify the default number of items in the initial list by supplying an argument to the
MAKELIST function. For example, the following statement makes a list that contains n
items:
carlist=makelist(n);
Each of the n items is initialized to a numeric missing value. Note that n can be any
nonnegative SCL numeric expression that is computed at run time, or it can be a simple
nonnegative numeric constant such as 12, if you want to create a list with a known initial
number of items. No matter how you create the list, you are free to expand or shrink it to
contain as many items as you need, from 0 to as many items as your computer has
memory to hold. To determine the length of a list, use the LISTLEN function.
Note: It is recommended that you declare lists with the LIST keyword to avoid
problems in calling overloaded methods. See “Overloading and List, Object, and
Numeric Types” on page 123
Example: Creating an SCL List
This section shows an SCL program that creates an SCL list, along with the output that
the program produces. The program reads the columns in DICTIONARY.TABLES, a
special read-only SQL view that stores information about all the SAS tables and SAS
views that are allocated in the current SAS session. The columns in this view are the
attributes (items of information) that are available for SAS tables. The example program
stores the column values in an SCL list that is sorted in table order (the order of the
columns in the ATTRIBUTES view), name order, and length order.
To create the view that lists the SAS tables, submit the following SQL procedure from
the PROGRAM EDITOR window:
/* Create the PROC SQL view ATTRIBUTES
/* which contains information about all
/* the members of type DATA in the SAS
/* data libraries that are associated
/* with the SAS session.
proc sql noprint;
create view attributes as
select *
from dictionary.tables
where memtype="DATA";
quit;
*/
*/
*/
*/
*/
56
Chapter 5
•
SCL Lists
The SCL program creates and displays an SCL list whose values come from the view
ATTRIBUTES.
/* Declare COLUMNS as a list */
declare list columns;
INIT:
/* Open the view ATTRIBUTES for reading */
attrs=open('attributes', 'I');
if (attrs > 0) then do;
/* Make a list containing the same
*/
/* number of items as the number of */
/* columns in the view ATTRS.
*/
numcols=attrn(attrs, 'NVARS');
columns=makelist(numcols);
do i=1 to numcols;
/* Set item I in list COLUMNS to */
/* the length of the column. The */
/* SETITEMN call is similar to
*/
/* the array assignment:
*/
/*
array{i} = colLen;
*/
colLen=varlen(attrs, i);
rc=setitemn(columns, colLen, i);
/* NAMEITEM gives item I the name */
/* of the Ith column
*/
colName=varname(attrs, i);
itemName=nameitem(columns, i, colName);
end;
sysrc=close(attrs);
/* Print the column names in their
*/
/* order in the SAS table. Sort by */
/* name and print. Then sort by
*/
/* length and print.
*/
rc=putlist(columns,'SAS Table Order:',0);
columns=sortlist(columns, 'NAME ASCENDING');
rc=putlist(columns, 'Name Order:', 0);
vars=sortlist(columns,'value');
rc=putlist(columns, 'Length Order:', 0);
/* Cleanup: delete the list */
rc=dellist(columns);
end;
else
_msg_=sysmsg();
return;
This program produces the following output:
SAS Table Order:(LIBNAME=8
MEMNAME=32
MEMTYPE=8
MEMLABEL=256
TYPEMEM=8
CRDATE=8
MODATE=8
NOBS=8
OBSLEN=8
NVAR=8
PROTECT=3
Initializing the Values in an SCL List
57
COMPRESS=8
REUSE=3
BUFSIZE=8
DELOBS=8
INDXTYPE=9
)[5]
Name Order:(BUFSIZE=8
COMPRESS=8
CRDATE=8
DELOBS=8
INDXTYPE=9
LIBNAME=8
MEMLABEL=256
MEMNAME=32
MEMTYPE=8
MODATE=8
NOBS=8
NVAR=8
OBSLEN=8
PROTECT=3
REUSE=3
TYPEMEM=8
)[5]
Length Order:(PROTECT=3
REUSE=3
BUFSIZE=8
COMPRESS=8
CRDATE=8
DELOBS=8
LIBNAME=8
MEMTYPE=8
MODATE=8
NOBS=8
NVAR=8
OBSLEN=8
TYPEMEM=8
INDXTYPE=9
MEMNAME=32
MEMLABEL=256
)[5]
Note: [5] is the list identifier that was assigned when this example was run and may be
different each time the example is run.
Initializing the Values in an SCL List
You can initialize an SCL list
•
in a DCL statement. For example, to create a list with the constants 1, 2, 'a', 3, 'b',
and 'c', you can declare the list as follows:
DCL list mylist={1,2,'a',3,'b','c'};
Your list may also contain sublists. For example:
58
Chapter 5
•
SCL Lists
DCL list mylist={1,2,'a',mysub={'A','B','C',
3,'b','c'}};
When you use the DECLARE statement to initialize an SCL list, you can use either
braces ({ and }) or brackets ([ and ]) to enclose a series of list items. For example,
both of the following list definitions are valid:
dcl list x = {1,2,3};
dcl list z = [4,5,6];
•
in an assignment statement after you have declared the list. For example, the
following assignment statement initializes the employee list with an employee ID,
name, and office location. The location is a sublist.
DCL list employee;
employee = {id=9999, name='Thomas',
locate={bldg='R', room='4321'}};
•
by specifying the InitialValue attribute when you create a class. In the following
example, the class InitVal initializes three list attributes, which also contain sublists.
class work.a.InitVal.class;
public list list1 / (InitialValue=
{COPY={
POPMENUTEXT='Copy here',
ENABLED='Yes',
METHOD='_drop'
},
MOVE={
POPMENUTEXT='Move here',
ENABLED='Yes',
METHOD='_drop'
}
}
);
public list list2 / (initialValue=
{1,2,3,{'abc','def',{1,2,'abc'},3},'def'});
public list list3 / (initialValue=
{id=888,name=Rob,
answers={mchoice={'a','c','b','e'},
math={1,4,8,9,}}
}
);
For more information about creating classes, see “CLASS” on page 249.
Note: Even if you initialize a list with a DCL or assignment statement or with the
initialValue attribute (rather than using one of the INSERT functions), you
must still explicitly delete the list as described in “Deleting Lists and List Items from
SCL Lists” on page 60.
Manipulating SCL Lists
You can create new lists and then insert numbers, character strings, objects, and even
other lists into them. You can replace or delete list items, and you can move them around
by reversing, rotating, or sorting a list. You can also assign names to the items in a list,
and you can refer to items by their names rather than by their index (position) in the list.
Inserting and Replacing Items in SCL Lists
59
Thus, you can use a list to implement data structures and to access and assign values to
list items by their names. Using this feature, you can add new fields to the list data
structure or change the order of the list's items without modifying your SCL program.
SCL lists are maintained entirely in memory. Keep this in mind as you develop your
applications. If your data is more appropriately maintained in a SAS table, you will
probably want to design your application in that manner instead of trying to read the
entire SAS table into a list. However, if you know your SAS table will not contain a
large number of rows and many columns, and if you do not need to maintain data
sharing, then you may find it convenient to read the SAS table into a list. That is, you
can use SCL lists for data that you would have liked to put into an array but could not
because of the restrictions imposed by arrays.
Determining the Type of an SCL List Item
In general, SCL list functions that process data values are suffixed with either N, C, L, or
O to denote the item types of numeric, character, list, or object, respectively. You can
use the ITEMTYPE function to determine the type of a list element and then use a
condition statement to determine which functions are used.
Passing SCL Lists as Arguments for Methods
Lists that are not declared as LIST type are treated by the compiler as numeric types in
order to maintain compatibility with Version 6. However, the more accurate
specification of LIST should be used, particularly when using lists in conjunction with
method overloading. For example, suppose you use the list MYLIST as an argument for
a method that has one version that takes a numeric argument and another that takes a list
argument. If MYLIST is not declared as LIST type, then it is treated as a numeric type
and the wrong method is called: the one that takes the numeric argument, instead of the
one that takes the list argument.
When a list with type LIST is passed as an argument to a method, SCL seeks a method
that accepts a LIST argument. If no exact type match is found, the list is passed to a
method that accepts an numeric argument. For example, if MYLIST is declared as LIST
type and is passed as an argument to method MYMETHOD, SCL will first search for a
MYMETHOD that accepts lists as arguments. If none is found, SCL will pass MYLIST
to a MYMETHOD that accepts numeric arguments.
Inserting and Replacing Items in SCL Lists
To insert and replace items in a list, use the SETITEMN, SETNITEMN, SETITEMC,
SETNITEMC, SETITEML, SETNITEML, SETITEMO, or SETNITEMO function.
These functions can assign values to existing items or they can add new items.
With arrays, you use
A{i}=x;
but with SCL lists, you use
rc=setitemn(listid,x,i);
60
Chapter 5
•
SCL Lists
To add a new item to a list without replacing the existing items, use the INSERTC,
INSERTL, INSERTN, or INSERTO function.
See also “Assigning Names to SCL List Items” on page 65.
Retrieving Values from SCL Lists
To retrieve the value of an item in a list, use the GETITEMN, GETNITEMN,
GETITEMC, GETNITEMC, GETITEML, GETNITEML, GETITEMO, or
GETNITEMO function.
With arrays, you use
x=A{i};
but with SCL lists, you use
x=getitemn(listid,i);
See also “Assigning Names to SCL List Items” on page 65.
Deleting Lists and List Items from SCL Lists
You can delete items from SCL lists by specifying the position, or index, of the item to
delete; by clearing all of the values from a list; or by deleting the entire list. You can also
pop items from lists, which enables you to create queues or stacks. See “Using SCL Lists
as Stacks and Queues” on page 68.
•
To delete a single list item, use the DELITEM or DELNITEM function, specifying
either the index or the name of the item to delete.
•
To clear all the values from a list, use the CLEARLIST function, which leaves the
list with a length of 0.
•
To delete an entire list, use the DELLIST function. This function returns to the
system the memory that was required for maintaining the list and its items.
Note: When you delete a list that has sublists, you should delete the list recursively if
you do not need to use the information in the sublists. When you do not delete a list,
the memory occupied by the list is not available for other tasks. To delete a list
recursively, specify Y as the value of the recursively argument in the DELLIST
function. For example:
rc=dellist(mylist,'Y');
For more information, see “Assigning Names to SCL List Items” on page 65 and
“DELLIST” on page 311.
Referencing SCL List Items by Index Number
List indexing is similar to array indexing. An index I specifies the position of an item in
the list. The first item is at index I=1, and the last item is at index I=LISTLEN(mylistid),
which is the length of the list. Thus, you can use DO loops to process all items in a list,
as shown in the following example:
Implementing SCL Sublists and Nested Structures
61
do i=1 to listlen(mylistid);
t=itemtype(mylistid,i);
put 'Item ' i ' is type ' t;
end;
Accessing Items Relative to the End of an SCL
List
It is also useful for you to be able to access items at or relative to the end of an SCL list.
You can use negative indices to index an item from the end of the list. Counting from the
end of a list, the last item is at index −1 and the first item is at position −n, where n is the
length of the list. Thus, you do not need to subtract indices from n to access items
relative to the end of the list. All of the SCL list functions recognize negative indices.
Index Errors in SCL Lists
Indexing errors occur when you supply an invalid index to an SCL list function, just as it
is an error to use an invalid array index. Valid values for list indexes depend on the
function. Some functions do not accept 0 as the index, whereas other functions do. Refer
to the index or start-index arguments in the dictionary entries for the SCL list functions.
Implementing SCL Sublists and Nested
Structures
Introduction
SCL allows you to put one list of items inside another SCL list, thereby making a sublist.
For example, you can read the columns of a SAS table row into a list. You could then
insert each row into another list, and repeat this process for a range of rows in the SAS
table. You then have a list of lists, where the "outer" list contains an element for each
row in the SAS table, and the "inner" sublists contain each row. These lists are called
nested lists.
To illustrate, consider the SAS table WORK.EMPLOYEES, created with the following
DATA step program:
data employees;
input fname $ 1-9 lname $ 10-18
position $ 19-28 salary 29-34;
datalines;
Walter
Bluerock Developer 36000
Jennifer Godfrey Manager
42000
Kevin
Blake
Janitor
19000
Ronald
Tweety
Publicist 29000
;
The following example reads the WORK.EMPLOYEES table into an SCL list. The
outer list is the list in the variable OUTERLIST. Each time through the loop, a new inner
62
Chapter 5
•
SCL Lists
list is created. Its identifier is stored in the variable INNERLIST, and INNERLIST is
inserted at the end of OUTERLIST.
INIT:
/* Open the EMPLOYEES table and
*/
/* create the SCL list OUTERLIST */
dsid=open('employees');
outerList=makelist();
/* Read the first table row and
*/
/* find the number of its columns */
rc=fetch(dsid);
numcols=attrn(dsid,'NVARS');
/* For each row, make a new INNERLIST */
/* and create and insert the sublists */
do while (rc=0);
innerList=makelist();
/* For each column, return the name */
/* and type. Insert a list item of */
/* that name and type into the
*/
/* row's INNERLIST.
*/
do i=1 to numcols;
name=varname(dsid,i);
type=vartype(dsid,i);
if type='N' then
rc=insertn(innerList,(getvarn
(dsid,i)),-1,name);
else
rc=insertc(innerList,(getvarc
(dsid,i)),-1,name);
end;
/* Insert each INNERLIST as an item */
/* into OUTERLIST and read the next */
/* row of the EMPLOYEES table
*/
outerList=insertl(outerList,innerList,-1);
rc=fetch(dsid);
end;
/* Close the EMPLOYEES table. Print and */
/* then delete OUTERLIST and its sublists. */
sysrc=close(dsid);
call putlist(outerList,'Nested Lists',2);
rc=dellist(outerList,'y');
return;
This program produces the following output:
Nested Lists( ( FNAME='Walter'
LNAME='Bluerock'
POSITION='Developer'
SALARY=36000
)[7]
1
( FNAME='Jennifer'
LNAME='Godfrey'
POSITION='Manager'
SALARY=42000
)[9]
1
( FNAME='Kevin'
LNAME='Blake'
Implementing SCL Sublists and Nested Structures
63
POSITION='Janitor'
SALARY=19000
)[11] 1
( FNAME='Ronald'
LNAME='Tweety'
POSITION='Publicist'
SALARY=29000
)[13] 1
)[5] 1
2
1
[5], [7], [9], [11], and [13] are the list identifiers that were assigned when this
example was run. These values may be different each time the example runs.
2
List identifier 5 identifies the "outer" list. Each row is an inner or nested list (list
identifiers 7, 9, 11, and 13).
Limitless Levels of Nesting
Nested lists are highly useful for creating collections of records or data structures. There
is no limit to the amount of nesting or to the number of sublists that can be placed in a
list, other than the amount of memory available to your SAS application. Further, you
can create recursive list structures, where the list A can contain other lists that contain A
either directly or indirectly. The list A can even contain itself as a list item.
Simulating Multidimensional Arrays with Nested Lists
You can declare multidimensional arrays in SCL, but all lists are one-dimensional. That
is, to access an item in a list, you specify only one index. However, you can use nested
lists to simulate multidimensional arrays. For example, to create a list structure that
mimics a 2 by 3 array, you can use the following example:
array a[2,3] 8 _temporary_;
init:
listid = makelist(2);
lista = setiteml(listid, makelist(3), 1);
listb = setiteml(listid, makelist(3), 2);
call putlist(listid);
do i = 1 to dim(a,1);
list=getiteml(listid,i);
do j = 1 to dim(a,2);
a[i, j] = 10*i + j;
put a[i,j]=;
rc = setitemn(list,a[i,j], j);
end;
end;
call putlist(listid);
return;
This example produces the following output:
((. . . )[7] (. . . )[9] )[5]
a[ 1 , 1 ]=11
a[ 1 , 2 ]=12
a[ 1 , 3 ]=13
a[ 2 , 1 ]=21
a[ 2 , 2 ]=22
64
Chapter 5
•
SCL Lists
a[ 2 , 3 ]=23
((11 12 13 )[7] (21 22 23 )[9] )[5]
Note: Not all of the program is shown here. You would need to delete these lists before
ending the program. [7], [9], and [5] are the list identifiers that were assigned when
this example was run and may be different each time the example is run.
Saving Nested Lists to SCL Entries
Introduction
When you save a list that contains sublists, both the list and its sublists are saved in the
same SLIST entry. Thus, if you create list data structures that are highly recursive and
have many cycles, you should be careful about saving your lists.
For example, suppose list A contains list B. When you save list A, you also save list B;
you do not need to save list B separately, because list B is already stored in list A. In
fact, if you store the lists in two separate SLIST entries and then try to read them back,
you do not get the same list structure that you stored originally.
The following example creates two lists, A and B, (with text values in them to identify
their contents) and inserts list B into list A. It then saves each list in separate SLIST
entries, A.SLIST and B.SLIST. Then, the program creates two more lists, APRIME and
BPRIME, reads the two saved SLIST entries into those two lists, and then prints all the
list identifiers and list values.
INIT:
/* Make lists A and B and insert an item */
/* of text into each list. Then, insert */
/* list B into list A.
*/
a = makelist();
a = insertc(a, 'This is list A');
b = makelist();
b = insertc(b, 'This is list B');
a = insertl(a, b);
/* Save lists A and B into separate */
/* SLIST entries.
*/
rc=savelist
('CATALOG','SASUSER.LISTS.A.SLIST', A);
rc=savelist
('CATALOG','SASUSER.LISTS.B.SLIST', B);
/* Make lists APRIME and BPRIME. Fill */
/* APRIME with the contents of A.SLIST */
/* and BPRIME with B.SLIST
*/
aPrime=makelist();
bPrime=makelist();
rc=fillist
('CATALOG','SASUSER.LISTS.A.SLIST', aPrime);
rc=fillist
('CATALOG','SASUSER.LISTS.B.SLIST', bPrime);
/* Store list APRIME into list BINA */
bInA = getiteml(aPrime);
put a= b= aPrime= bPrime= bInA= ;
call putlist(a, 'List A:',0);
call putlist(b, 'List B:',0);
call putlist(aPrime, "List aPrime:",0);
Assigning Names to SCL List Items
65
call putlist(bPrime, "List bPrime:",0);
/* Delete list A and its sublist B */
/* Delete lists APRIME, BPRIME, and BINA */
rc=dellist(a,'y');
rc=dellist(aPrime);
rc=dellist(bPrime);
return;
Here is the output:
a=5 b=7 aPrime=9 bPrime=11 bIna=13
List A:(('This is list B
)[7]
'This is list A
)[5]
List B:('This is list B
)[7]
List aPrime:(('This is list B
)[13]
'This is list A
)[9]
List bPrime:('This is list B
)[11]
Note that the sublist B (13) that was read from A.SLIST is not the same as the sublist
BPRIME (11) that was read from B.SLIST. That is, A contains B, but B does not contain
BPRIME. Therefore, changes made to B are inherently reflected in A, whereas changes
to BPRIME are not reflected in APRIME.
Also note that the structures of list A and list APRIME are the same, but the list
identifiers are different and do not match any of the list identifiers that were read from
B.SLIST.
Note: [5], [7], [9], [11], and [13] are the list identifiers that were assigned when this
example was run and may be different each time the example runs.
Advantages of SAVELIST Recursiveness
There is an advantage to the recursive nature of the SAVELIST function. For example, if
list A contains sublists B and C, SAVELIST saves all three lists when you save A to an
SLIST entry. Your application can take advantage of this if you have several unrelated
lists that you want to save. By creating a new list and inserting the lists that you want
saved into the new list, you can save them all in one SLIST entry with one SAVELIST
call, instead of saving each sublist in a separate SLIST entry with separate SAVELIST
calls.
Assigning Names to SCL List Items
Introduction
SCL supports a feature called named lists, which enable you to assign a name to each
item in a list, or only to some list items. The name can be any SCL character string, not
just character strings that are valid SAS column names, unless the list has the
SASNAMES attribute. The maximum length of an SCL list item name is 255 characters.
As with SAS names, list item names can contain mixed-case characters—for example,
EmployeeLocation.
66
Chapter 5
•
SCL Lists
If you search a list for which the HONORCASE attribute has not been set, then SCL will
uppercase the item names for the search operation only. The item names are not
permanently changed to uppercase.
You can use the GETNITEMC, GETNITEMN, GETNITEML, and GETNITEMO
functions to access named list items by their name rather than by their position. This
feature enables you to vary the contents of the list according to your application needs
without having to keep track of where a particular item is located in a list. To assign or
replace values that are associated with a name, use the SETNITEMC, SETNITEMN,
SETNITEML, or SETNITEMO function. To delete an item by its name, use the
DELNITEM function.
Item names in a list do not have to be unique unless the NODUPNAMES attribute has
been assigned to the list. Item names are stored as they are entered. If the list has the
HONORCASE attribute (the default), then 'abc' and 'Abc' are two different item names.
Otherwise, if the list has the IGNORECASE attribute, these names are duplicate names.
To search for an item by its name, you use the NAMEDITEM function. If the list has the
HONORCASE attribute, this function searches for item names that match the case
specified for the search unless you use the FORCE-UP attribute for NAMEDITEM. This
attribute overrides the HONORCASE attribute and converts the item name to upper case
for the search. However, the case of the item name is converted only for the search; the
name continues to be stored as you entered it. The function ignores trailing blanks when
searching for a matching name. If a list contains duplicate names, the search function
finds the first occurrence of the name unless you have specified a different occurrence of
the item for the search. By inserting a new item at the beginning of the list, you can
“hide” a previous value because a named search will find your new item first by default.
To restore the previous value, simply delete the new item from the list.
You can freely mix named items with unnamed items in a list. You can also use both
kinds of indexing (by name or by index) in any list, regardless of how the list was
created or whether all, some, or no items have names.
Indexing a Named Item by its Position
To find the index of a named item in a list, use the NAMEDITEM function. This enables
you to access an item later by its index in the list, which is a faster search. However,
searching by index is not safe if the index of the item might change between the time
you find the index and the time you use the index.
The following statement replaces the value associated with the first occurrence of the
item named ACME in the list NUMBERS with the value (201) 555-2263. These
statements do not modify the list if the name ACME is not found:
i=nameditem(numbers,'Acme');
if i>0 then
rc=setitemc(numbers,'(201) 555-2263',i);
Determining or Replacing an Item's Name
To replace the name of an item, use the NAMEITEM function. You can also use
NAMEITEM when you want to find out the name of an item but you do not want to
change the item's name.
Using SCL Lists in Shared Data Environments
67
Finding an Occurrence of a Name
In general, the functions that enable you to access a list item by its name operate on the
first occurrence of the name by default. However, you can combine the optional
arguments occurrence, start-index, and ignore-case to refer to items other than the first
occurrence. Occurrence enables you to specify the number of the occurrence of a named
item that you want to find. For example, a value of three references the third occurrence,
and a value of ten references the tenth occurrence. The following example demonstrates
how to find the indexes of the first and third item named SCL:
/* default occurrence is 1
*/
first=nameditem(listid,'SCL');
/* Find the third occurrence */
third=nameditem(listid,'SCL',3);
Specifying Where the Search for an Item Starts
The start-index argument specifies the position in the list in which to begin the search
for a named item. The default is 1, which starts the search at the first item in the list. If
the value for start-index is negative, then the search starts at position ABS(start-index)
from the end of the list and searches toward the front of the list. For example, a startindex of −1 references the list's last item, whereas a start-index of −2 references the list's
second-to-last item. Thus, to change the value of the last occurrence of a list item named
X to the value y, you can use a statement like the following:
listid=setnitemn(listid,y,'X',1,-1);
Using SCL Lists in Shared Data Environments
Introduction
SCL lists support shared data environments. (Without a shared data environment, if you
wanted an entry to pass data to many other entries, you had to pass the data explicitly in
each CALL DISPLAY statement, or else you had to put the values in macro variables.
However, macro variables are limited in the amount of data they can contain (only scalar
values), and their names must be valid SAS names.) By placing data in a shared data
environment, other programs and even other SAS applications can retrieve the data via a
name. These names can be any valid SCL string, and the value associated with a name
can be a numeric value, a character value, or an entire list.
The two kinds of shared data environments are implemented with local SCL lists and
global SCL lists.
Local Data Environment
Each SAS software application (such as an FSEDIT application, or a SAS/AF
application started with the AF command) maintains its own application environment in
a local environment list. You can store information that is local to the application, but
which you want to be shared among all of an application's entries, in this local
environment list. The function ENVLIST('L') returns the list identifier of the
environment list for the current application. Other applications' lists are maintained in
68
Chapter 5
•
SCL Lists
the memory of each application, and even though two lists in different applications may
have the same list identifier, the lists are actually different. This is analogous to the same
SAS table identifier being used by different SAS applications: the identifier actually
refers to different SAS tables that are opened at different times.
Global Data Environment
There is also a global environment list that stores data that can be shared across all SAS
applications started in the same SAS session or process. For example, one SAS
application may place some data in the global environment list and then close. Another
application may then open and read the data that was created by the first application. To
access the global environment list, use the list identifier returned by ENVLIST('G').
Using SCL Lists as Stacks and Queues
You can create lists that function as stacks (first in, last out lists) or queues (first in, first
out lists).
Using a List as a Stack
To use a list as a stack, use the INSERTC, INSERTN, INSERTL, or INSERTO function
to insert items into a list. The default insertion position for these functions is the
beginning of the list, so you need only specify the list identifier and the data to be
inserted.
To pop (or delete) an item from a stack, use the POPN, POPC, POPL, or POPO function.
You can use the ITEMTYPE function to determine the type of the item at the top of the
stack if your application does not know the type. If your application always puts the
same data type onto your stack (for example, if the stack is a stack of character strings
and you use only INSERTC to put items into the list), then you do not need to use
ITEMTYPE to check the type of the item at the top of the stack before popping.
If you do not want to keep the top value, use the DELITEM or DELNITEM function to
delete the top item in the stack.
To replace the top item, use the SETITEMN, SETITEMC, SETITEML, or SETITEMO
function.
You should not attempt to pop or delete an item unless you are sure the list contains at
least one item. You can use the LISTLEN function to return the length of the list before
you use a function to pop or delete an item.
Using a List as a Queue
When you use a list as a queue, you also use the INSERTN, INSERTC, INSERTL, or
INSERTO function to put items in the list. However, you use an item index of −1 to
insert an item at the end of the list.
To remove an item from a queue, use the POPN, POPC, POPL, or POPO function. As
with stacks, you should use the ITEMTYPE and LISTLEN functions to verify the item's
type and the list's length before popping an item from the list. Here is an example:
INIT:
listid=makelist();
rc=insertc(listid,'1st',-1);
Using SCL List File Functions
69
rc=insertc(listid,'2nd',-1);
rc=insertc(listid,'3rd',-1);
rc=insertc(listid,'4th',-1);
rc=insertc(listid,'5th',-1);
put 'Test of first in, first out queue:';
do i=1 to listlen(listid);
cval=popc(listid);
put 'Popping item' i cval=;
end;
rc=dellist(listid);
return;
This program produces the following output:
Test of
Popping
Popping
Popping
Popping
Popping
first in, first out queue:
item 1 cval=1st
item 2 cval=2nd
item 3 cval=3rd
item 4 cval=4th
item 5 cval=5th
Assigning Attributes to SCL Lists and List Items
You can assign attributes to lists or to items in a list. Attributes are useful for controlling
the use and modification of lists. For example, you can specify that a list is not available
for update, which means that other programs called by your program (for example, via
CALL DISPLAY) cannot change the data in the list or cannot add or delete items from
the list. You can also assign attributes such as NOUPDATE or NODELETE to
individual items in a list.
Because it is easy to change the type of any item in a list simply by replacing the value
with a new value, it would be quite easy for one application to accidentally change a list
in a way that you did not intend. To prevent this possibility, you may want to specify
that a list or items in a list have a fixed type. When you assign the proper attributes to the
lists and items that you create, you do not need to worry about other parts of the
application corrupting your data, and you can avoid adding data validation statements to
your programs.
Assigning list and item attributes is not required. However, doing so can facilitate
application development, because an attempt to violate an attribute, which indicates a
bug in the application, causes the application to stop with a fatal error.
To set the attributes of a list or item, use the SETLATTR function. The GETLATTR
function returns a string that describes the current attributes. The HASATTR function
returns 1 if the list or item has the specified attribute and 0 if it does not.
Using SCL List File Functions
Two SCL list functions enable you to store lists in SAS catalog entries or in external
files and to read lists from these files. The SAVELIST function stores a list, and the
FILLIST function reads data from a catalog entry or external file and fills a list with the
text from the file.
70
Chapter 5
•
SCL Lists
Debugging SCL Lists
SCL provides a List Diagnostic Utility (or list analyzer), which reports any SCL lists that
are not freed at the appropriate time in a program. SCL lists that are not deleted when
they are no longer needed can waste significant amounts of memory. The list analyzer
highlights every statement in an SCL program that creates an SCL list that is not deleted
directly or indirectly by the program.
To use the list analyzer, issue the command SCLPROF LIST ON from any SAS window
to start the data collection phase. Then invoke the window associated with the program
that you want to test. When you return to the window from which you issued the
SCLPROF LIST ON command, issue the command SCLPROF LIST OFF to end the
data collection phase. The data collected during this phase is stored in the SAS table
WORK.SCLTRAC1. If you end the task from which you started the data collection
phase, the data collection phase ends.
Note: To avoid collecting lists that are not deleted until the end of the task or
application, begin the data collection phase on the second invocation of the window
that you are testing.
As soon as the data collection phase ends, the interactive data presentation phase begins.
From the data presentation phase, you can save the data by selecting Save As from the
File menu. To view the stored data, issue the command SCLPROF LIST
DATA=analysis-data-set.The interactive presentation phase opens two windows:
•
The SUMMARY window displays summary statistics of the list analysis.
•
The List Diagnostic Utility window lists the catalog entries containing SCL
programs that created lists that were not deleted during the analysis.
If warnings were generated during the analysis, a third window opens to display the
warning messages.
71
Chapter 6
Controlling Program Flow
Introduction to SCL Program Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Using SCL DO Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
DO Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Iterative DO Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
DO WHILE Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
DO UNTIL Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Controlling DO Loops (CONTINUE and LEAVE) . . . . . . . . . . . . . . . . . . . . . . . . . 75
Using SCL SELECT-WHEN/OTHERWISE Conditions . . . . . . . . . . . . . . . . . . . . . 76
Using SCL IF-THEN/ELSE Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Using the SCL RETURN Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Branching to a Labeled Section (LINK) in SCL Programs . . . . . . . . . . . . . . . . . . . 78
Branching to Another Entry (GOTO) in SCL Programs . . . . . . . . . . . . . . . . . . . . . 79
Calling SCL Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Stopping Execution of the Current Section in SCL Programs . . . . . . . . . . . . . . . . . 80
Executing Methods in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Using the SCL CONTROL Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Introduction to SCL Program Flow
You can control the flow of execution of your SCL application by
•
using any of several programming constructs such as DO loops and IF/THEN-ELSE
statements
•
branching to labeled sections with the LINK statement
•
branching to PROGRAM, FRAME, MENU, CBT, or HELP entries with the GOTO
statement
•
branching to another SCL entry with CALL DISPLAY
•
executing a method that is stored in a separate SCL entry with CALL METHOD
•
executing an object method by using dot notation
•
sending a method to an object with CALL SEND
72
Chapter 6
•
Controlling Program Flow
•
sending a method to a FRAME entry control with CALL NOTIFY
•
specifying how labeled sections are executed, when and where submit blocks are
executed, and whether execution halts when errors are encountered in dot notation
with the CONTROL statement
•
creating a program halt handler to control how run-time errors are processed.
For more information about controlling the flow of execution in applications that use
frames, refer to the Guide to SAS/AF Applications Development.
Using SCL DO Loops
Introduction
There are four forms of the DO statement:
•
The DO statement designates a group of statements that are to be executed as a unit,
usually as a part of IF-THEN/ELSE statements.
•
The iterative DO statement executes a group of statements repetitively based on the
value of an index variable. If you specify an UNTIL clause or a WHILE clause, then
the execution of the statements is also based on the condition that you specify in the
clause.
•
The DO UNTIL statement executes a group of statements repetitively until the
condition that you specify is true. The condition is checked after each iteration of the
loop.
•
The DO WHILE statement executes a group of statements repetitively as long as the
condition that you specify remains true. The condition is checked before each
iteration of the loop.
For more information about DO statements, in addition to the information in this
documentation, refer to SAS Statements: Reference.
DO Statement
The DO statement designates a group of statements that are to be executed as a unit. The
simplest form of the DO loop is
DO;
. . .SAS statements. . .
END;
This simple DO statement is often used within IF-THEN/ELSE statements to designate a
group of statements to be executed if the IF condition is true. For example, in the
following code, the statements between DO and END are performed only when YEARS
is greater than 5.
if years>5 then
do;
months=years*12;
put years= months=;
end;
Using SCL DO Loops
73
Iterative DO Loops
Introduction
The iterative DO loop executes the statements between DO and END repetitively based
on the value of an index variable.
DO index-variable = start TO stop <BY increment>;
Note: In SCL applications, both start and stop are required, and start, stop, and
increment must be numbers or expressions that yield a number. The TO and BY
clauses cannot be reversed, and start cannot be a series of items separated by
commas. You can use only one start TO stop specification (with or without the BY
clause) in a DO loop.
If increment is not specified, then index-variable is increased by 1. If increment is
positive, then start must be the lower bound and stop must the be upper bound for the
loop. If increment is negative, then start must be the upper bound and stop must be the
lower bound for the loop.
The values of index-variable, stop, and increment are evaluated at each iteration of the
loop. Any changes made to index-variable, stop, or increment within the DO group can
affect the number of times that the loop executes. For example, if you change the value
of index-variable inside of the DO group, then index-variable may never equal the value
of stop, and the loop will not stop executing.
For more understanding of what DO LOOP elements are updated, examine the following
code and the generated output:
INIT:
dcl num k=18 n=11;
do i=k+2 to n-1 by -2;
put i=;
end;
dcl num s=1 e=25;
do i = s to e;
e = e - 5;
s = s + 10;
put i= e= s=;
end;
RETURN;
i=20
i=18
i=16
i=14
i=12
i=10
i=1 e=20 s=11
i=2 e=15 s=21
i=3 e=10 s=31
i=4 e=5 s=41
i=5 e=0 s=51
The following code uses the DOPEN and DNUM functions to execute SAS statements
once for each file in the current directory:
rc=filename('mydir','.');
74
Chapter 6
•
Controlling Program Flow
dirid=dopen('mydir');
do i=1 to dnum(dirid);
...SAS statements...
end;
rc=dclose(dirid);
Using UNTIL and WHILE Clauses
You can add either an UNTIL clause or a WHILE clause to your DO statements.
DO index-variable = start TO stop <BY increment>
<WHILE (expression)> | <UNTIL (expression)>;
The UNTIL expression is evaluated after the statements in the DO loop have executed,
and the WHILE expression is evaluated before the statements in the DO loop have
executed. The statements in a DO UNTIL loop are always executed at least once, but the
statements in a DO WHILE loop will not execute even once if the DO WHILE
expression is false.
If index-variable is still in the range between start and stop, then if you specify an
UNTIL clause, the DO group will execute until the UNTIL expression is true. If you
specify a WHILE clause, the loop will execute as long as the WHILE expression is true.
The following example uses an UNTIL clause to set a flag, and then it checks the flag
during each iteration of the loop:
flag=0;
do i=1 to 10 until(flag);
...SAS statements...
if expression then flag=1;
end;
The following loop executes as long as I is within the range of 10 to 0 and MONTH is
equal to JAN.
do i=10 to 0 by -1 while(month='JAN');
...SAS statements...
end;
DO WHILE Statement
The DO WHILE statement works like the iterative DO statement with a WHILE clause,
except that you do not specify an index-variable or start, stop, or increment.
DO WHILE (expression);
. . .SAS statements. . .
END;
Whether the loop executes is based solely on whether the expression that you specify
evaluates to true or false. The expression is evaluated before the loop executes, and if the
expression is false, then the loop is not executed. If the expression is false the first time it
is evaluated, then the loop will not execute at all.
For example, the following DO loop is executed once for each value of N: 0, 1, 2, 3, and
4.
n=0;
do while(n<5);
put n=;
n+1;
Using SCL DO Loops
75
end;
DO UNTIL Statement
The DO UNTIL statement works like the iterative DO statement with an UNTIL clause,
except that you do not specify an index variable nor start, stop, or increment.
DO UNTIL (expression);
. . .SAS statements. . .
END;
Whether the loop executes is based solely on whether the expression that you specify
evaluates to true or false. The loop is always executed at least once, and the expression is
evaluated after the loop executes.
For example, the following DO loop is executed once for each value of N: 0, 1, 2, 3, and
4.
n=0;
do until(n>=5);
put n=;
n+1;
end;
Controlling DO Loops (CONTINUE and LEAVE)
You can use the CONTINUE and LEAVE statements to control the flow of execution
through DO loops.
The CONTINUE statement stops the processing of the current DO loop iteration and
resumes with the next iteration of the loop. For example, the following code reads each
row in the DEPT table, and if the status is not PT, it displays a frame that enables the
user to update the full-time employee's salary.
deptid=open('dept');
call set(deptid);
do while (fetch(deptid) ne -1);
if (status='PT') then continue;
newsal=display('fulltime.frame');
end;
The LEAVE statement stops processing the current DO loop and resumes with the next
statement after the DO loop. With the LEAVE statement, you have the option of
specifying a label for the DO statement:
LEAVE <label>;
If you have nested DO loops and you want to skip out of more than one loop, you can
specify the label of the loop that you want to leave. For example, the following LEAVE
statement causes execution to skip to the last PUT statement:
myloop:
do i=1 to 10;
do j=1 to 10;
if j=5 then leave myloop;
put i= j=;
end;
end;
76
Chapter 6
•
Controlling Program Flow
put 'this statement executes next';
return;
In SCL applications, the LEAVE statement can be used only within DO loops, not in
SELECT statements (unless it is enclosed in a DO statement).
For more information, refer to “CONTINUE” on page 272 , “LEAVE” on page 494 ,
and SAS Statements: Reference.
Using SCL SELECT-WHEN/OTHERWISE
Conditions
The SELECT statement executes one of several statements or groups of statements
based on the value of the expression that you specify.
SELECT< (select-expression)>;
WHEN-1 (when-expression-1) statement(s);
<WHEN-n (when-expression-n) statement(s);>
<OTHERWISE statement;>
END;
SAS evaluates select-expression, if present, as well as when–expression-1. If the values
of both expressions are equal, then SAS executes the statements associated with whenexpression-1. If the values are not equal, then SAS evaluates when-expression-n, and if
the values of select–expression-1 and when-expression-1 are equal, SAS executes the
statements associated with when-expression-n. SAS evaluates each when expression
until it finds a match or until it has evaluated all of the when expressions without finding
a match. If you do not specify a select expression, then SAS evaluates each when
expression and executes only the statements associated with the first when expression
that evaluates to true.
If the value of none of the when expressions matches the value of the select expression,
or if you do not specify a select expression and all of the when expressions are false,
then SAS executes the statements associated with the OTHERWISE statement. If you do
not specify an OTHERWISE statement, the program halts.
In SCL applications, you cannot specify a series of when expressions separated by
commas in the same WHEN statement. However, separating multiple WHEN statements
with a comma is equivalent to separating them with the logical operator OR, which is
acceptable in SCL applications.
The statements associated with a when expression can be any executable SAS statement,
including SELECT and null statements. A null statement in a WHEN statement causes
SAS to recognize a condition as true and to take no additional action. A null statement in
an OTHERWISE statement prevents SAS from issuing an error message when all of the
when expressions are false.
Each WHEN statement implies a DO group of all statements until the next WHEN or
OTHERWISE statement. Therefore the following program is valid:
select (paycat);
when ('monthly')
amt=salary;
when ('hourly')
amt=hrlywage*min(hrs,40);
Using SCL IF-THEN/ELSE Conditions
77
if hrs>40 then put 'Check timecard.';
otherwise put 'problem observation';
end;
However, if you need to include a LEAVE statement as part of your WHEN statement,
then you must explicitly specify the DO statement in your WHEN statement.
You can specify expressions and their possible values in either of the following ways:
•
SELECT;
WHEN (variable operator value) statement(s);
END;
•
SELECT (variable);
WHEN (value) statement(s);
END;
For example, both of the following SELECT statements are correct:
select;
when (x<=5) put '1 to 5';
when (x>=6) put '6 to 10';
end;
select (x);
when (1) put 'one';
when (2) put 'two';
end;
The following code is incorrect because it compares the value of the expression X with
the value of the expression X=1. As described in “Boolean Numeric Expressions” on
page 34 , in Boolean expressions, a value of 0 is false and a value of 1 is true. Therefore,
the expression X is false and the expression X=1 is false, so the program prints x is 1.
x=0;
select (x);
when (x=0) put 'x is 0';
when (x=1) put 'x is 1';
otherwise put x=;
end;
See also “SELECT (execute a statement)” on page 644 and the SAS Statements:
Reference.
Using SCL IF-THEN/ELSE Conditions
The IF-THEN/ELSE statement executes a statement or group of statements based on a
condition that you specify.
IF expression THEN statement;
<ELSE statement;>
If expression is true, then SAS executes the statement in the THEN clause. If the
expression is false and if an ELSE statement is present, then SAS executes the ELSE
statement. The statement following THEN and ELSE can be either a single SAS
statement (including an IF-THEN/ELSE statement) or a DO group.
For example:
if (exist(table)) then
78
Chapter 6
•
Controlling Program Flow
_msg_='SAS table already exists.';
else do;
call new(table,'',1,'y');
_msg_='Table has been created.';
end;
Suppose your application is designed to run in batch mode and you do not want to
generate any messages. You could use a null statement after THEN:
if (exist(table)) then;
else call new(table,'',1,'y');
Using the SCL RETURN Statement
The RETURN statement stops the execution of the program section that is currently
executing.
RETURN <value>;
The RETURN statement at the end of a reserved program section (FSEINIT ,INIT,
MAIN, TERM, and FSETERM) sends control to the next program section in the
sequence.
The first RETURN statement after a LINK statement returns control to the statement that
immediately follows the LINK statement.
When the RETURN statement is encountered at the end of a window variable section,
control returns to the next section in the program execution cycle. That next section may
be another window variable section or it may be the MAIN section. When the current
program execution cycle finishes, control returns to the application window.
The RETURN statement at the end of a method returns control to the calling program.
The RETURN statement for an ENTRY or METHOD block can return value if the
ENTRY or METHOD statement contains RETURN=data-type. The returned value has
no effect if control does not immediately return to the calling program.
For an example of the RETURN statement, see the example in “Branching to Another
Entry (GOTO) in SCL Programs” on page 79. For more explanation and an additional
example, see “RETURN” on page 619.
Branching to a Labeled Section (LINK) in SCL
Programs
The LINK statement tells SCL to jump immediately to the specified statement label.
LINK label;
SCL then executes the statements from the statement label up to the next RETURN
statement. The RETURN statement sends program control to the statement that
immediately follows the LINK statement. The LINK statement and the label must be in
the same entry.
The LINK statement can branch to a group of statements that contains another LINK
statement; that is, you can nest LINK statements. You can have up to ten LINK
statements with no intervening RETURN statements.
Branching to Another Entry (GOTO) in SCL Programs
79
See “Branching to Another Entry (GOTO) in SCL Programs” on page 79 for an
example that includes LINK statements.
For more information, refer to the “LINK Statement” in SAS Statements: Reference.
Branching to Another Entry (GOTO) in SCL
Programs
You can use the GOTO statement to transfer control to another SAS/AF entry.
CALL GOTO (entry<, action<, frame>>);
Entry specifies a FRAME, PROGRAM, MENU, CBT, or HELP entry. By default, when
the entry ends, control returns to the parent entry that was specified in entry. If a parent
entry is not specified, then the window exits.
For example, suppose WORK.A.A.SCL contains the following code:
INIT:
link SECTONE;
put 'in INIT after link to SECTONE';
return;
SECTONE:
put 'in SECTONE before link to TWO';
link TWO;
put 'in SECTONE before goto';
call goto('work.a.b.frame');
put 'in SECTONE after goto to frame';
return;
TWO:
put 'in TWO';
return;
WORK.A.B.SCL contains the following code:
INIT:
put 'in WORK.A.B.FRAME';
return;
If you compile WORK.A.B.FRAME and WORK.A.A.SCL, and then test
WORK.A.A.SCL, you will see the following output:
in
in
in
in
SECTONE before link to TWO
TWO
SECTONE before goto
WORK.A.B.FRAME
The PUT statement in the INIT section of A.SCL and the last PUT statement in
SECTONE are never executed. After WORK.A.B.FRAME is displayed and the user
exits from the window, the program ends.
For more information, see “GOTO” on page 439.
80
Chapter 6
•
Controlling Program Flow
Calling SCL Entries
SAS/AF software provides SCL entries for storing program modules. SCL programs can
access a module that is stored in another SCL entry. They can pass parameters to the
module and can receive values from the module. An SCL module can be used by any
other SCL program.
You call an SCL module with a CALL DISPLAY routine that passes parameters to it
and receives values that are returned by the SCL entry. The module's ENTRY statement
receives parameters and returns values to the calling program.
For example, if you were creating an SCL module to validate amounts and rates that are
entered by users, you could store the labeled sections in separate SCL entries named
AMOUNT.SCL and RATE.SCL. Then, you could call either of them with a CALL
DISPLAY statement like the following:
call display('methdlib.validate.amount.scl',amount,error);
For more information, see “DISPLAY” on page 326.
Stopping Execution of the Current Section in SCL
Programs
The STOP statement stops the execution of the current section. If a MAIN or TERM
section is present, control passes to MAIN or TERM. For example, in the following
program, control passes from INIT to SECTONE. Since X=1 is true, the STOP
statement is executed, so control never passes to TWO. Control passes directly from the
STOP statement in SECTONE to MAIN. The STOP statement at the end of MAIN has
no effect, and control passes to TERM.
INIT:
put 'beginning INIT';
x=1;
link SECTONE;
put 'in INIT after link';
stop;
MAIN:
put 'in MAIN';
stop;
SECTONE:
put 'in SECTONE';
if x=1 then stop;
link TWO;
return;
TWO:
put 'in TWO';
return;
TERM:
Using the SCL CONTROL Statement
81
put 'in TERM';
return;
This program produces the following output:
beginning INIT
in SECTONE
in MAIN
in TERM
For more information, see “STOP” on page 680.
Executing Methods in SCL Programs
In object-oriented applications, methods are implemented in CLASS blocks or
USECLASS blocks. These methods are usually invoked with dot notation. See
“Accessing Object Attributes and Methods with Dot Notation” on page 132 for
information about dot notation.
You can also send methods to an object by using CALL SEND, and you can send a
method to a control in a FRAME entry by using CALL NOTIFY. See “SEND” on page
649 and “NOTIFY” on page 569 for more information.
Methods may also be stored in SCL, PROGRAM, or SCREEN entries. If the method is
stored in an SCL entry, then call the method with the CALL METHOD routine. If the
method is stored in a PROGRAM or SCREEN entry, you can use the LINK or GOTO
statements to call it.
See Also
•
“Calling a Method That Is Stored in an SCL Entry” on page 14
•
“Branching to a Labeled Section (LINK) in SCL Programs” on page 78
•
“Branching to Another Entry (GOTO) in SCL Programs” on page 79
Using the SCL CONTROL Statement
The CONTROL statement enables you to specify options that control the execution of
labeled sections, the formatting of submit blocks, and whether an error in dot notation
causes a program halt.
CONTROL options;
You can specify the following options with the CONTROL statement:
ALLCMDS | NOALLCMDS
determines whether SCL can intercept procedure-specific or custom commands that
are issued in the application. This option also determines if and when the MAIN
section executes.
ALWAYS | NOALWAYS
determines whether the MAIN section executes if the user enters a command that
SCL does not recognize.
82
Chapter 6
•
Controlling Program Flow
ASIS NOASIS
determines whether SCL eliminates unnecessary spaces and line breaks before
submit blocks are submitted.
BREAK label | NOBREAK
enables you to specify a labeled program section that will be executed if an interrupt
or break occurs while your program is executing.
HALTONDOATTRIBUTE | NOHALTONDOTATTRIBUTE
determines whether execution halts if SCL finds an error in the dot notation that is
used in your program.
ENDSAS | NOENDSAS
determines whether the TERM section executes when the user enters the ENDSAS
or BYE commands.
ENDAWS | NOENDAWS
determines whether the TERM section executes when a user ends a SAS session by
selecting the system closure menu in a FRAME entry that is running within the SAS
application workspace.
ENTER | NOENTER
determines whether the MAIN section executes when the user presses the ENTER
key or a function key without modifying a window variable.
ERROR | NOERROR
determines whether the MAIN section executes if a control or field contains a value
that causes an attribute error.
LABEL | NOLABEL
determines whether the MAIN section executes before or after the window variable
sections.
TERM | NOTERM
determines whether the TERM section executes even if a user does not modify any
columns in the current row of the SAS table.
For more information, see “CONTROL” on page 274.
83
Chapter 7
Using SCL with Other SAS
Software Products
Introduction to Using SCL with SAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Using SAS DATA Step Features in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . 84
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Submitting SAS Statements and SQL Statements in SCL Programs . . . . . . . . . . . 87
Submitting Statements Compared to Using SCL Features . . . . . . . . . . . . . . . . . . . 87
Designating Submit Blocks in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
How Submit Blocks Are Processed in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . 88
How Submitted Statements Are Formatted in SCL Programs . . . . . . . . . . . . . . . . 90
Modifying the Behavior of Submit Blocks in SCL Programs . . . . . . . . . . . . . . . . . . 90
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Controlling Where Submitted Code Is Executed . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Controlling What Happens After a Submit Block Executes . . . . . . . . . . . . . . . . . . 91
Submitting Statements to a Remote Host . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Substituting Text in Submit Blocks in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . 92
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
How Values Are Substituted in Submit Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Specifying Text for Substitutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Issuing Commands to Host Operating Systems from SCL Programs . . . . . . . . . . . 94
Using Macro Variables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Storing and Retrieving Macro Variable Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Using the Same Name for Macro Variables and SCL Variables . . . . . . . . . . . . . . . 95
Using Automatic Macro Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
SCL and DATA Step Graphics Interface Elements . . . . . . . . . . . . . . . . . . . . . . . . . 96
BASE SAS Functions Used in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Differences Between SCL Functions and BASE Functions . . . . . . . . . . . . . . . . . . 101
TRIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
BASE SAS Statements Used in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
BASE SAS CALL Routines Used in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
84
Chapter 7
•
Using SCL with Other SAS Software Products
Introduction to Using SCL with SAS
SCL provides many of the same features as the Base SAS language. However, some
SCL features differ slightly in functionality from Base SAS language features. Also,
although SCL provides a rich set of features, it does not provide functions and
statements to accomplish directly all of the data access, management, presentation, and
analysis tasks that SAS software can perform, nor can it provide the equivalent for every
command that is available under your host operating system. However, SCL does
provide the following features:
•
the SUBMIT statement, which provides access to other features of SAS software by
generating SAS statements and then submitting them to SAS software for
processing.
•
the SYSTEM function, which provides access to host operating systems by issuing
host operating system commands.
Using SAS DATA Step Features in SCL Programs
Introduction
SCL supports the syntax of the SAS DATA step with the exceptions and additions noted.
Refer to SAS Statements: Reference for details about the SAS language elements that are
available in the DATA step.
SCL does not support the DATA step statements that relate specifically to creating SAS
data tables, such as the DATA, SET, INFILE, and DATALINES statements. However,
SCL does provide special functions that can perform equivalent SAS table
manipulations. See “Introduction to Using SAS Tables in SCL Programs” on page 180
for details.
Statements
The ARRAY, DO, LENGTH, PUT, and SELECT statements behave differently in SCL
than in the DATA step. The differences are fully documented in their entries in the
Chapter 13, “SAS Component Language Dictionary,” on page 209. The following list
shows the DATA step statements that are valid in SCL programs and notes differences
between a statement's support in SCL and in the DATA step.
ARRAY (Explicit)
defines the elements of an explicit array. _NUMERIC_, _CHARACTER_, and
_ALL_ are not supported.
assignment
assigns values to variables.
comment
documents the purpose of a program.
Using SAS DATA Step Features in SCL Programs
85
CONTINUE
stops the processing of the current DO loop and resumes with the next iteration of
that DO loop. See the dictionary entries for DO as well as CONTINUE for
information about the differences in the behavior of this statement in SCL.
DO, iterative DO, DO-UNTIL, DO-WHILE
repetitively execute one or more statements. SCL does not support the DO-list form
of the DO statement, but it does support LEAVE and CONTINUE statements that
extend the capabilities of DO-group processing.
END
designates the end of a DO group or SELECT group.
GOTO
jumps to a specified program label.
IF-THEN-ELSE
enables conditional execution of one or more statements.
%INCLUDE
accesses statements (usually from an external file) and adds them to the program
when the SCL program compiles.
LEAVE
stops executing the current DO group and resumes with the next sequential
statement. See the dictionary entries for DO as well as LEAVE for information about
the differences in the behavior of this statement in SCL.
LENGTH
allocates storage space for character and numeric variables. In SCL, the LENGTH
statement can set only the lengths of nonwindow variables.
LINK
jumps to a specified program label but allows a return to the following statement.
SCL allows nesting of up to 25 LINK statements.
NULL
is an executable statement that contains a semicolon (;) and acts as a place holder.
PUT
writes text to the LOG window.
RETURN
returns control or a value to the calling routine or application. In SCL, RETURN can
also return a value from the execution of a method.
RUN
is an alias for the RETURN statement.
SELECT-WHEN
enables conditional execution of one or several statements or groups of statements.
STOP
is an alias for the RETURN statement.
SUM
adds the result of an expression to an accumulator variable.
Functions
The following list notes differences between a function's support in SCL and in the
DATA step.
86
Chapter 7
•
Using SCL with Other SAS Software Products
DIF
Not supported in SCL.
LAG
Not supported in SCL.
SUM
SCL does not support the colon modifier in the SUM function that is used to sum all
variables that start with a certain string.
See SAS Functions and CALL Routines: Reference for details about other DATA step
functions that are supported by SCL.
Variables
Introduction
Variables in SCL programs share most of the characteristics of variables in the DATA
step such as default length and type. However, you should be aware of the differences
described in the following sections. In addition, SCL variables can be declared to be
local in scope to a DO or SELECT block.
Numeric Variables
A variable is assigned the numeric data type if its data type is not explicitly declared.
Character Variables
In SCL, the length of a character variable is determined as follows:
•
For window variables, the maximum length of a variable is equal to the length of the
corresponding control or field in the window.
•
For character-type nonwindow variables, the length is 200 characters unless a
different length is explicitly declared. However, you can use the DECLARE or
LENGTH statement to change the length from a minimum of 1 character to a
maximum of 32K characters. The maximum length of a nonwindow variable is not
affected by the length of a string that is assigned to the variable in the SCL program.
For example, suppose your SCL program contains the following statement and that
the window for the application does not include a field named LongWord:
LongWord='Thisisaverylongword';
As a result of this assignment statement, SCL creates a nonwindow variable named
LongWord with a maximum length of 200 characters. The length of the string in the
assignment statement has no effect on the maximum length of the variable. By
contrast, this same assignment in a DATA step would create a variable with a
maximum length of 19 characters.
As in the DATA step, the LENGTH function in SCL returns the current trimmed
length of a string (the position of the nonblank character at the right end of the
variable value). However, SCL also provides the MLENGTH function, which returns
the maximum length of a character variable, as well as the LENGTH function with
the NOTRIM option, which returns the untrimmed length of a string.
Expressions
SCL supports the standard DATA step expressions in an identical manner. The only
exception is the IN operator, which has the following syntax:
Submitting Statements Compared to Using SCL Features
87
i=variable IN (list-of-values)|array-name;
In SCL, the IN operator returns the index of the element if a match is found, or it returns
0 if no match is found. However, in the DATA step, the IN operator returns 1 if a match
is found and 0 if no match is found. The IN operator is valid for both numeric and
character lists as well as for arrays. If a list that is used with the IN operator contains
values with mixed data types, then those values are converted to the data type of the first
value in the list when the program is compiled.
In the following example, the statements using the IN operator are equivalent:
array list{3}$ ('cat','bird','dog');
i='dog' in ('cat','bird','dog');
i='dog' in list;
In SCL, this example produces I=3, whereas in the DATA step the example produces
I=1. Also, the DATA step does not support the form i='dog' in list.
Submitting SAS Statements and SQL Statements
in SCL Programs
SCL programs can submit statements to execute both DATA steps and all the procedures
in any product in SAS software. SCL programs can also submit Structured Query
Language (SQL) statements directly to SAS software's SQL processor without
submitting a PROC SQL statement. SQL statements enable you to query the contents of
SAS files and to create and manipulate SAS tables and SAS views. SCL programs also
enable you to submit command line commands to the Program Editor window for
processing. Finally, SCL programs can submit statements for processing on your local
host or on a remote host, if SAS/CONNECT software is installed at your site.
Submitting Statements Compared to Using SCL
Features
You should submit statements when the task you want to perform is difficult or
impossible using SCL features alone. Whenever equivalent SCL features are available, it
is more efficient to use them than to submit SAS statements. For example, the following
two sets of statements produce the same result, opening an FSEDIT window to display
the SAS data table WORK.DATA1 for editing:
/* This uses the SCL Feature. */
call fsedit('work.data1');
/* This uses submitted statements. */
submit continue;
proc fsedit data=work.data1;
run;
endsubmit;
From within an application, fewer computer resources are required to execute the CALL
routine in SCL than to submit statements to SAS software. Thus, the CALL routine is a
better choice unless you need features of the procedure that the CALL routine does not
provide (for example, the VAR statement in PROC FSEDIT to select which variables to
display to the user).
88
Chapter 7
•
Using SCL with Other SAS Software Products
Designating Submit Blocks in SCL Programs
In SCL programs, you designate statements to be submitted to SAS software for
processing by placing them in submit blocks. A submit block begins with a SUBMIT
statement, ends with an ENDSUBMIT statement, and consists of all the statements in
between. The following statements illustrate these characteristics:
SUBMIT; 1
proc print data=work.data1;
var a b c;
2
run;
endsubmit;
3
2
1
The SUBMIT statement starts the submit block.
2
These statements are submitted to SAS software when the program executes.
3
The ENDSUBMIT statement ends the submit block.
For details, see “SUBMIT” on page 682.
How Submit Blocks Are Processed in SCL
Programs
Figure 7.1 on page 89 illustrates how submit blocks are processed when they are
executed (not when they are compiled). Submit blocks are not processed when you test a
SAS/AF application with the TESTAF command.
How Submit Blocks Are Processed in SCL Programs
Figure 7.1
89
Default Processing of Submit Blocks
SCL Program
submit;
proc print data=work.datal;
var a b c;
run;
1
endsubmit;
Preview Buffer
proc print data=work.datal;
var a b c;
run;
2
SAS Supervisor
DATA Step Compiler
Procedure Parser
3
SQL Processor
1. All of the code between a SUBMIT statement and the next ENDSUBMIT statement
is copied into a special storage area called the preview buffer. The submitted code is
not checked for errors when it is copied to the preview buffer. Errors in the
submitted code are not detected until the statements or commands are executed.
2. The text in the preview buffer is scanned, and any requested substitutions are made.
Substitution is discussed in “Substituting Text in Submit Blocks in SCL Programs”
on page 92.
3. The contents of the preview buffer are submitted to SAS software for execution. You
can specify options to change where and when the contents of the preview buffer are
submitted and to specify the actions that the SCL program takes after the statements
are submitted. See “Modifying the Behavior of Submit Blocks in SCL Programs” on
page 90 for details.
Note: By default, code is not submitted immediately when the submit block is
encountered in an executing program. Also, when a nested entry (that is, an entry
that is called by another entry in the application) contains a submit block, the
submitted code is not executed until the calling task ends, or until another submit
block with a CONTINUE or IMMEDIATE option is encountered. Simply ending the
entry that contains the submit block does not process submitted code.
Note: Issuing the DM command inside of a SUBMIT block may cause the submitted
statements to be executed in an unexpected order. You may want to use the CALL
EXECCMD or EXECCMDI routine instead to issue your command.
90
Chapter 7
•
Using SCL with Other SAS Software Products
How Submitted Statements Are Formatted in SCL
Programs
By default, SCL reformats the submitted code when it copies it to the preview buffer. To
conserve space, all leading and trailing spaces in the submitted text are removed.
Semicolons in the submitted statements cause line breaks in the submitted text.
In some situations (for example, when the submitted code includes lines of raw data),
you may want to prevent this formatting by SCL. You can do this by using a CONTROL
statement with the ASIS option. When an SCL program contains a CONTROL ASIS
statement, SCL honors the indention and spacing that appears in the submit block.
Programs that use CONTROL ASIS are more efficient because the time spent on
formatting is reduced. A CONTROL NOASIS statement restores the default behavior.
Modifying the Behavior of Submit Blocks in SCL
Programs
Introduction
You can modify the default SCL processing of submit blocks by specifying options in
the SUBMIT statement. SUBMIT statement options control the following behaviors:
•
when the code in the preview buffer is submitted for execution
•
when the submitted code is processed and what happens after the submitted code is
executed
•
whether the submitted code is executed in the local SAS session or in a remote SAS
session.
Controlling Where Submitted Code Is Executed
By default, code that is collected in the preview buffer using SUBMIT blocks is sent to
SAS software for execution. SCL provides options for the SUBMIT statement that alter
the default behavior. If you specify the CONTINUE option in the SUBMIT statement,
you can control where code is submitted with the following options:
COMMAND
submits the code in the preview buffer to the command line of the next window that
is displayed. The code should contain valid commands for that window; otherwise,
either errors are reported or the submitted commands are ignored.
EDIT
sends the code in the preview buffer to the Program Editor window. You can modify
your code in the Program Editor window and then submit it for execution.
SQL
submits the code in the preview buffer to SAS software's SQL processor, from both
TESTAF and AF modes. The SUBMIT SQL option enables you to submit the SQL
statements without having to specify a PROC SQL statement. Submitting SQL
Modifying the Behavior of Submit Blocks in SCL Programs
91
statements directly to the SQL processor is more efficient than submitting PROC
SQL statements.
Controlling What Happens After a Submit Block Executes
Introduction
SCL also provides SUBMIT statement options that you can use to control what action, if
any, the application takes after a submit block executes. These options are CONTINUE,
IMMEDIATE, PRIMARY, and TERMINATE. Without one of these options, the code in
a submit block is simply passed to the preview buffer, the application continues
executing, and the code in the submit block is not processed by SAS software until the
application ends.
CONTINUE
suspends program execution while the submit block executes and then continues
program execution at the statement that immediately follows the ENDSUBMIT
statement. (CONTINUE is the only SUBMIT option that is valid in FSEDIT and
FSBROWSE applications.)
IMMEDIATE
stops program execution after the generated statements are submitted. Use this
option with caution. Using this option in a labeled section that is executed
individually when a CONTROL LABEL statement is in effect can prevent the
execution of other labeled sections. A program in a FRAME entry does not compile
if it contains a SUBMIT IMMEDIATE statement.
PRIMARY
returns the program to the application's initial window after the generated statements
are submitted. This option is useful when you want all the intermediate windows to
close and you want control to return to a primary window in the current execution
stream. This option causes looping if the current program is the primary window.
TERMINATE
stops the SAS/AF task after the statements in the submit block are processed. This
option is useful when an application does not need to interact with users after the
submitted statements are processed. However, use TERMINATE with caution
because re-invoking the application can be time-consuming.
Using SUBMIT CONTINUE in FSEDIT Applications
The behavior of a SUBMIT CONTINUE block in an FSEDIT application depends on
how the application was invoked.
•
If you invoked the application with a PROC FSEDIT statement, then the statements
in the submit block cannot be processed until the FSEDIT session ends, even when
you specify SUBMIT CONTINUE. The statements cannot be executed as long as the
FSEDIT procedure is executing.
•
If you invoked the application with an FSEDIT command or with a CALL FSEDIT
routine from another SCL program, then the statements in the submit block can
execute immediately as long as no other procedure is currently executing.
Submitting Statements to a Remote Host
By default, statements in a submit block are executed for processing on the local host. If
SAS/CONNECT software is available at your site, you can also submit statements for
92
Chapter 7
•
Using SCL with Other SAS Software Products
processing on a remote host. To send submitted statements to a remote host, use the
following form of the SUBMIT statement:
submit remote;
...SAS or SQL statements to execute
on a remote host...
endsubmit;
In situations where an application user can switch between a remote host and the local
host, the user can issue the REMOTE command to force all submits to be sent to a
remote host. The syntax of the REMOTE command is REMOTE <ON|OFF>. If neither
ON nor OFF is specified, the command acts like a toggle.
The REMOTE option in the SUBMIT block takes precedence over a REMOTE
command that is issued by an application user. A SAS/AF application must have a
display window in order to issue and recognize the REMOTE command. Before SCL
submits the generated code for execution, it checks to see whether the user has issued the
REMOTE ON command. If a user has issued the command, SCL checks to see whether
the remote link is still active. If the remote link is active, SCL submits the code for
execution. If the remote link is not active, SCL generates an error message and returns.
The preview buffer is not cleared if the submit fails.
Substituting Text in Submit Blocks in SCL
Programs
Introduction
In interactive applications, values for statements in a submit block may need to be
determined by user input or program input in the application. An SCL feature that
supports this requirement is the substitution of text in submit blocks, based on the values
of fields or SCL variables.
How Values Are Substituted in Submit Blocks
SCL performs substitution in submit blocks according to the following rules:
•
When SCL encounters a name that is prefixed with an ampersand (&) in a submit
block, it checks to see whether that name is the name of an SCL variable. If it is, then
SCL substitutes the value of that variable for the variable reference in the submit
block. For example, suppose a submit block contains the following statement:
proc print data=&table;
If the application includes a variable named TABLE whose value is work.sample,
then this statement is passed to the preview buffer:
proc print data=work.sample;
•
If the name that follows the ampersand does not match an SCL variable, then no
substitution occurs. The name is passed unchanged (including the ampersand) with
the submitted statements. When SAS software processes the statements, it attempts
to resolve the name as a macro variable reference. SCL does not resolve macro
variable references within submit blocks. For example, suppose a submit block
contains the following statement:
Substituting Text in Submit Blocks in SCL Programs
93
proc print data=&table;
If there is no SCL variable named TABLE in the application, then the statement is
passed unchanged to the preview buffer. SAS software attempts to resolve &TABLE
as a macro reference when the statements are processed.
CAUTION:
Avoid using the same name for both an SCL variable and a macro variable that
you want to use in submitted statements. SCL substitutes the value of the
corresponding SCL variable for any name that begins with an ampersand. To
guarantee that a name is passed as a macro variable reference in submitted
statements, precede the name with two ampersands (for example, &&TABLE).
Specifying Text for Substitutions
Introduction
If an SCL variable that is used in a substitution contains a null value, then a blank is
substituted for the reference in the submitted statements. This can cause problems if the
substitution occurs in a statement that requires a value, so SCL allows you to define a
replacement string for the variable. If the variable's value is not blank, the complete
replacement string is substituted for the variable reference. To define a replacement
string, you can use either the Replace attribute (for a control or field) or the REPLACE
statement.
Using the REPLACE Statement
The REPLACE statement acts as an implicit IF-THEN statement that determines when
to substitute a specified string in the submit block. Consider the following example:
replace table 'data=&table';
...more SCL statements...
submit;
proc print &table;
run;
endsubmit;
If the SCL variable TABLE contains ' ' (or _BLANK_), then these statements are
submitted:
proc print;
run;
If the SCL variable TABLE contains work.sample, then these statements are
submitted:
proc print data=work.sample;
run;
Using the Replace Attribute
In SAS/AF applications, you can also can define replacement strings for a window
variable using the Replace attribute in the properties window (for a control) or the
attribute window (for a field). The text that you specify for the Replace attribute is
substituted for the variable name when the variable name is preceded with an ampersand
in submitted statements.
94
Chapter 7
•
Using SCL with Other SAS Software Products
Issuing Commands to Host Operating Systems
from SCL Programs
SCL programs can use the SYSTEM function to issue commands to host operating
systems. For example, an SCL program may need to issue commands to the operating
system in order to perform system-specific data management or control tasks or to
invoke external applications.
An SCL program can issue any command that is valid for the operating system under
which an application runs. SCL places no restrictions on commands that are issued to an
operating system, nor does SCL check command strings for validity before passing them
to the operating system.
Using Macro Variables in SCL Programs
Introduction
Macro variables, which are part of the macro facility in Base SAS software, can be used
in SCL programs. Macro variables are independent of any particular SAS table,
application, or window. The values of macro variables are available to all SAS software
products for the duration of a SAS session. For details, refer to macro variables in SAS
Macro Language: Reference. In SCL programs, you can
•
store values in macro variables (for example, to pass information from the current
SCL program to subsequent programs in the application, to subsequent applications,
or to other parts of SAS software).
•
retrieve values from macro variables (for example, to pass information to the current
SCL program from programs that executed previously or from other parts of SAS
software, or to pass values from one observation to another in FSEDIT applications).
Examples of types of information that you frequently need to pass between entries in an
application include
•
names of SAS tables to be opened
•
names of external files to be opened
•
identifiers of open SAS tables
•
file identifiers of open external files
•
the current date (instead of using date functions repeatedly)
•
values to be repeated across rows in an FSEDIT session.
Storing and Retrieving Macro Variable Values
To assign a literal value to a macro variable in an SCL program, you can use the
standard macro variable assignment statement, %LET. For example, the following
statement assigns the literal value sales (not the value of an SCL variable named
SALES) to a macro variable named DSNAME:
Using Macro Variables in SCL Programs
95
%let dsname=sales;
Macro variable assignments are evaluated when SCL programs are compiled, not when
they are executed. Thus, the %LET statement is useful for assigning literal values at
compile time. For example, you can use macro variables defined in this manner to store
a value or block of text that is used repeatedly in a program. However, you must use a
different approach if you want to store the value of an SCL variable in a macro variable
while the SCL program executes (for example, to pass values between SCL programs).
Macro variables store only strings of text characters, so numeric values are stored as
strings of text digits that represent numeric values. To store values so that they can be
retrieved correctly, you must use the appropriate CALL routine. The following routines
store the value of a macro when an SCL program runs:
CALL SYMPUT
stores a character value in a macro variable.
CALL SYMPUTN
stores a numeric value in a macro variable.
For example, the following CALL routine stores the value of the SCL variable SALES
in the macro variable TABLE:
call symput('table',sales);
To retrieve the value of a macro variable in an SCL program, you can use a standard
macro variable reference. In the following example, the value of the macro variable
TABLE is substituted for the macro variable reference when the program is compiled:
dsn="&table";
The function that you use to retrieve the value of a macro variable determines how the
macro variable value is interpreted. The following functions return the value of a macro
variable when a program runs:
SYMGET
interprets the value of a macro variable as a character value.
SYMGETN
interprets the value of a macro variable as a numeric value.
Using the Same Name for Macro Variables and SCL Variables
Using the same name for a macro variable and an SCL variable in an SCL program does
not cause a conflict. Macro variables are stored in SAS software's global symbol table,
whereas SCL variables are stored in the SCL data vector (SDV). However, if your
program uses submit blocks and you have both a macro variable and an SCL variable
with the same name, then a reference with a single ampersand substitutes the SCL
variable. To force the macro variable to be substituted, reference it with two ampersands
(&&). The following example demonstrates using a reference that contains two
ampersands:
dsname='sasuser.class';
call symput('dsname','sasuser.houses');
submit continue;
proc print data=&dsname;
run;
proc print data=&&dsname;
run;
endsubmit;
96
Chapter 7
•
Using SCL with Other SAS Software Products
The program produces the following:
proc print data=sasuser.class;
run;
proc print data=sasuser.houses;
run;
Using Automatic Macro Variables
In addition to macro variables that you define in your programs, SAS software provides
a number of predefined macro variables for every SAS session or process. These
automatic macro variables supply information about the current SAS session or process
and about the host operating system on which the SAS session is running. For example,
you can use the automatic macro variable SYSSCP to obtain the name of the current
operating system. Automatic macro variables are documented in SAS Macro Language:
Reference.
When you use automatic macro variables, remember to use the appropriate routines and
functions to set and retrieve variable values. For example, consider the following
program statements. The first uses a macro variable reference:
jobid="&sysjobid";
The second uses an SCL function:
jobid=symget('sysjobid');
The macro variable reference, designated by the & (ampersand), is evaluated when the
program is compiled. Thus, the identifier value for the job or process that compiles the
program is assigned to the variable JOBID. Assuming that the preceding two statements
were compiled by an earlier SAS process, if you want the JOBID variable to contain the
identifier for the current process, then you must use the second form (without the &).
The SYMGET function extracts the macro variable value from the global symbol table
at execution.
Note: The values that are returned by SYSJOBID and other automatic macro variables
depend on your host operating system.
SCL and DATA Step Graphics Interface Elements
If SAS/GRAPH software is installed at your site, you can use the functions and CALL
routines provided in the DATA Step Graphics Interface (DSGI) to create graphics output
from SAS Component Language programs.
BASE SAS Functions Used in SCL
The following SAS language functions are also available in SCL:
Arithmetic Functions
•
ABS
•
DIM
•
HBOUND
BASE SAS Functions Used in SCL
•
LBOUND
•
MOD
•
SIGN
•
SQRT
Sample Statistic Functions
•
CSS
•
CV
•
KURTOSIS
•
MAX
•
MEAN
•
MIN
•
N
•
NMISS
•
ORDINAL
•
RANGE
•
SKEWNESS
•
STD
•
STDERR
•
SUM
•
USS
•
VAR
Truncation Functions
•
CEIL
•
FLOOR
•
FUZZ
•
INT
•
ROUND
•
TRUNC
Random Number Functions
•
NORMAL
•
RANBIN
•
RANCAU
•
RANEXP
•
RANGAM
•
RANNOR
•
RANPOI
•
RANTBL
97
98
Chapter 7
•
Using SCL with Other SAS Software Products
•
RANTRI
•
RANUNI
•
UNIFORM
Mathematical Functions
•
DIGAMMA
•
ERF
•
ERFC
•
EXP
•
GAMMA
•
LGAMMA
•
LOG
•
LOG10
•
LOG2
•
TRIGAMMA
Financial Functions
•
COMPOUND
•
DACCDB
•
DACCDBSL
•
DACCSL
•
DACCSYD
•
DACCTAB
•
DEPDB
•
DEPDBSL
•
DEPSL
•
DEPSYD
•
DEPTAB
•
INTRR
•
IRR
•
MORT
•
NETPV
•
NPV
•
SAVING
Trigonometric Functions
•
ARCOS
•
ARSIN
•
ATAN
•
COS
BASE SAS Functions Used in SCL
•
COSH
•
SIN
•
SINH
•
TAN
•
TANH
Character Functions
•
BYTE
•
COLLATE
•
COMPRESS
•
INDEX
•
INDEXC
•
LEFT
•
LENGTH
•
RANK
•
REPEAT
•
REVERSE
•
RIGHT
•
SCAN
•
SUBSTRN
•
TRANSLATE
•
TRIM
•
UPCASE
•
VERIFY
Probability Functions
•
POISSON
•
PROBBETA
•
PROBBNML
•
PROBCHI
•
PROBF
•
PROBGAM
•
PROBHYPR
•
PROBNEGB
•
PROBNORM
•
PROBT
Date and Time Functions
•
DATE
•
DATEJUL
99
100
Chapter 7
•
Using SCL with Other SAS Software Products
•
DATEPART
•
DATETIME
•
DAY
•
DHMS
•
HMS
•
HOUR
•
INTCK
•
INTNX
•
JULDATE
•
MDY
•
MINUTE
•
MONTH
•
QTR
•
SECOND
•
TIME
•
TIMEPART
•
TODAY
•
WEEKDAY
•
YEAR
•
YYQ
Quantile Functions
•
BETAINV
•
CINV
•
FINV
•
GAMINV
•
PROBIT
•
TINV
State and Zip Code Functions
•
FIPNAME
•
FIPNAMEL
•
FIPSTATE
•
STFIPS
•
STNAME
•
STNAMEL
•
ZIPCITY
•
ZIPCITYDISTANCE
•
ZIPFIPS
BASE SAS Statements Used in SCL 101
•
ZIPNAME
•
ZIPNAMEL
•
ZIPSTATE
Special Functions
•
INPUT
•
PUT
•
SYMGET
Differences Between SCL Functions and BASE
Functions
TRIM
The TRIM function in SCL returns a null string when given a string of blanks. This is in
contrast to the BASE DATA step TRIM function, which returns a string with a single
blank when given a string of blanks. For an example, see the following SCL code and
output:
init:
/*Trims trailing spaces. */
a= 'first
';
b= trim(a)||'Last';
put b;
/*Trims all spaces and returns a null string. */
x= '
';
y= ">"||trim(x)||"<";
put y;
return
Output:
firstLast
><
BASE SAS Statements Used in SCL
•
ARRAY Reference
•
Assignment
•
Comment
•
DO
•
DO, Iterative
102
Chapter 7
•
Using SCL with Other SAS Software Products
•
DO UNTIL
•
DO WHILE
•
END
•
GO TO
•
IF-THEN/ELSE
•
LENGTH
•
LINK
•
RETURN
•
SELECT
BASE SAS CALL Routines Used in SCL
•
RANBIN
•
RANCAU
•
RANEXP
•
RANGAM
•
RANNOR
•
RANPOI
•
RANTBL
•
RANTRI
•
RANUNI
103
Part 2
Developing Object-Oriented
Applications
Chapter 8
SAS Object-Oriented Programming Concepts . . . . . . . . . . . . . . . . . . . 105
Chapter 9
Example: Creating An Object-Oriented Application in SCL . . . . . . . 151
104
105
Chapter 8
SAS Object-Oriented
Programming Concepts
Introduction to Object-Oriented Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Object-Oriented Programming and the SAS Component Object Model . . . . . . . 107
Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Relationships among Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Types of Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Defining Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Instantiating Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Defining Method Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Defining Method Names and Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Specifying Parameter Types and Storage Types . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Passing Objects as Arguments for Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Returning Values From Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Method Signatures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Forward-Referencing Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Overloading Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Overriding Existing Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Defining Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Implementing Methods Outside of Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Method Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Creating Attributes Automatically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Specifying Where an Attribute Value Can Be Changed . . . . . . . . . . . . . . . . . . . . 129
Setting Initial Values and the List of Valid Values . . . . . . . . . . . . . . . . . . . . . . . . 129
Associating Custom Access Methods with Attributes . . . . . . . . . . . . . . . . . . . . . . 130
Linking Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Attribute Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Accessing Object Attributes and Methods with Dot Notation . . . . . . . . . . . . . . . . 132
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
What Happens When Attribute Values Are Set or Queried . . . . . . . . . . . . . . . . . . 135
Events and Event Handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
System Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
106
Chapter 8
•
SAS Object-Oriented Programming Concepts
Defining and Sending Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Defining Event Handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Event and Event Handler Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
139
139
140
141
Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Defining Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Converting Version 6 Non-Visual Classes to SCOM Classes . . . . . . . . . . . . . . . . . 145
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Removing Global Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Declaring Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Converting Labels and LINK Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Converting CALL SEND to Dot Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
Converting Class Definitions with CREATESCL . . . . . . . . . . . . . . . . . . . . . . . . . 148
Using Instance Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Introduction to Object-Oriented Programming
Object-oriented programming (OOP) is a technique for writing computer software. The
term object oriented refers to the methodology of developing software in which the
emphasis is on the data, while the procedure or program flow is de-emphasized. That is,
when designing an OOP program, you do not concentrate on the order of the steps that
the program performs. Instead, you concentrate on the data in the program and on the
operations that you perform on that data.
Advocates of object-oriented programming claim that applications that are developed
using an object-oriented approach
•
are easier to understand because the underlying code maps directly to real-world
concepts that they seek to model
•
are easier to modify and maintain because changes tend to involve individual objects
and not the entire system
•
promote software reuse because of modular design and low interdependence among
modules
•
offer improved quality because they are constructed from stable intermediate classes
•
provide better scalability for creating large, complex systems.
Object-oriented application design determines which operations are performed on which
data, and then groups the related data and operations into categories. When the design is
implemented, these categories are called classes. A class defines the data and the
operations that you can perform on the data. In SCL, the data for a class is defined
through the class's attributes, events, event handlers, and interfaces. (Legacy classes
store data in instance variables.) The operations that you perform on the data are called
methods.
Objects are data elements in your application that perform some function for you.
Objects can be visual objects that you place on the frame—for example, icons, push
buttons, or radio boxes. Visual objects are called controls; they display information or
accept user input.
Objects can also be nonvisual objects that manage the application behind the scenes; for
example, an object that enables you to interact with SAS data sets may not have a visual
Object-Oriented Programming and the SAS Component Object Model
107
representation but still provides you with the functionality to perform actions on a SAS
data set such as accessing variables, adding data, or deleting data. An object or
component is derived from, or is an instance of, a class. The terms object, component,
and instance are interchangeable.
Software objects are self-contained entities that possess three basic characteristics:
behavior
a collection of operations that an object can perform on itself or on other objects.
Methods define the operations that an object can perform. For example, you can use
the _onGeneric method in sashelp.classes.programHalt.class to trap all
generic errors.
state
a collection of attributes and their current values. Two of the programHalt
component's attributes are stopExecution (which determines whether the
program continues to execute after the program halt occurs) and dump (which
contains the program-halt information). You can set these values through SCL.
identity
a unique value that distinguishes one object from another. This identifier is referred
to as its object identifier. The object identifier is created by SCL when you
instantiate an object with the _NEW_ operator. This identifier is also used as the
first-level qualifier in SCL dot notation.
The following sections describe how object-oriented techniques and related concepts are
implemented in SCL.
Object-Oriented Programming and the SAS
Component Object Model
The SAS Component Object Model (SCOM) provides a flexible framework for SCL
component developers. With SCOM, you can develop model components that
communicate with viewer components that are built with other SAS software (such as
SAS/AF and webAF) or with software from other vendors.
A component in SCOM is a self-contained, reusable object that has specific properties,
including
•
a set of attributes and methods
•
a set of events that the object sends
•
a set of event handlers that execute in response to various types of events
•
a set of supported or required interfaces.
With SCL, you can design components that communicate with each other, using any of
the following processes:
Attribute linking
enabling a component to change one of its attributes when the value of another
attribute is changed.
Model/view communication
enabling a view (typically a visual control) to communicate with a model, based on a
set of common methods that are defined in an interface.
108
Chapter 8
•
SAS Object-Oriented Programming Concepts
Event handling
enabling a component to send an event that another component can respond to by
using an associated event handler.
Note, however, that drag and drop operations can be defined only through SAS/AF
software, not through SCL.
Classes form the foundation of the SCOM architecture by defining these attributes,
methods, events, event handlers and interfaces. There are two ways to construct a class
that uses the SAS Component Object Model:
•
You can build a class with the Class Editor that is available in SAS/AF software.
•
You can use SCL class syntax to construct a class.
This chapter provides detailed information about using SCL to create and modify
classes.
Classes
Introduction
A class defines a set of data and the operations you can perform on that data. Subclasses
are similar to the classes from which they are derived, but they may have different
properties or additional behavior. In general, any operation that is valid for a class is also
valid for each subclass of that class.
Relationships among Classes
Introduction
Classes that you define with SCL can support two types of relationships:
•
inheritance
•
instantiation.
Inheritance
Generally, the attributes, methods, events, event handlers, and interfaces that belong to a
parent class are automatically inherited by any class that is created from it. One
metaphor that is used to describe this relationship is that of the family. Classes that
provide the foundation for other classes are called parent classes, and classes that are
derived from parent classes are child classes. When more than one class is derived from
the same parent class, these classes are related to each other as sibling classes. A
descendent of a class has that class as a parent, either directly or indirectly through a
series of parent-child relationships. In object-oriented theory, any subclass that is created
from a parent class inherits all of the characteristics of the parent class that it is not
specifically prohibited from inheriting. The chain of parent classes is called an ancestry.
Classes
Figure 8.1
109
Class Ancestry
Class
Selection
Model
All SCOM Models...
Object
Frame
All other objects...
Widget
Visual
Controls...
V6 Legacy
Widgets
Whenever you create a new class, that class inherits all of the properties (attributes,
methods, events, event handlers, and interfaces) that belong to its parent class. For
example, the Object class is the parent of all classes in SAS/AF software. The Frame and
Widget classes are subclasses of the Object class, and they inherit all properties of the
Object class. Similarly, every class you use in a frame-based application is a descendent
of the Frame, Object, or Widget class, and thus inherits all the properties that belong to
those classes.
Instantiation
In addition to the inheritance relationship, classes have an instantiation or an “is a”
relationship. For example, a frame is an instance of the Frame class; a radio box control
is an instance of the Radio Box Control class; and a color list object is an instance of the
Color List Model class.
All classes are instances of the Class class. The Class class is a metaclass. A metaclass
collects information about other classes and enables you to operate on other classes. For
more information about metaclasses, see “Metaclasses” on page 110.
Types of Classes
Introduction
Some SAS/AF software classes are specific types of classes.
•
Abstract classes
•
Models and views
•
Metaclasses.
Abstract Classes
Abstract classes group attributes and methods that are common to several subclasses.
These classes themselves cannot be instantiated; they simply provide functionality for
their subclasses.
The Widget class in SAS/AF software is an example of an abstract class. Its purpose is
to collect properties that all widget subclasses can inherit. The Widget class cannot be
instantiated.
110
Chapter 8
•
SAS Object-Oriented Programming Concepts
Models and Views
In SAS/AF software, components that are built on the SAS Component Object Model
(SCOM) framework can be classified either as views that display data or as models that
provide data. Although models and views are typically used together, they are
nevertheless independent components. Their independence allows for customization,
flexibility of design, and efficient programming.
Models are non-visual components that provide data. For example, a Data Set List model
contains the properties for generating a list of SAS data sets (or tables), given a specific
SAS library. A model may be attached to multiple views.
Views are components that provide a visual representation of the data, but they have no
knowledge of the actual data they are displaying. The displayed data depends on the
state of the model that is connected to the view. A view can be attached to only one
model at a time.
It may be helpful to think of model/view components as client/server components. The
view acts as the client and the model acts as the server.
For more information on interfaces, see “Interfaces” on page 142. For more information
on implementing model/view communication, refer to Guide to SAS/AF Applications
Development.
Metaclasses
As previously mentioned, the Class class (sashelp.fsp.Class.class) and any
subclasses you create from it are metaclasses. Metaclasses enable you to collect
information about other classes and to operate on those classes.
Metaclasses enable you to make changes to the application at run time rather than only at
build time. Examples of such changes include where a class's methods reside, the default
values of class properties, and even the set of classes and their hierarchy.
Metaclasses also enable you to access information about parent classes, subclasses, and
the methods and properties that are defined for a class. Specifically, through methods of
the Class class, you can
•
retrieve information about an application, such as information about the application's
structure, which classes are being used, and which legacy classes use particular
instance variables. Each class has a super class that is accessed by the _getSuper
method. Every class also maintains a list of subclasses that is accessed with the
_getSubclassList and _getSubclasses methods.
•
list the instances of a class and process all of those instances in some way. Each class
maintains a list of its instances. You can use _getInstanceList and _getInstances to
process all the instances.
•
create objects and classes at run time with the _new method. Instances of the
metaclass are other classes.
For more information about metaclasses, see the Class class in the SAS/AF online Help.
Defining Classes
Introduction
You can create classes in SCL with the CLASS block. The CLASS block begins with
the CLASS statement and ends with the ENDCLASS statement:
<ABSTRACT> CLASS class-name<EXTENDS parent-class-name>
Classes
111
<SUPPORTS supports-interface-clause>
<REQUIRES requires-interface-clause>
< / (class-optional-clause)>
<(attribute-statements)>
<(method-declaration-statements)>
<(method-implementation-blocks)>
<(event-declaration-statements)>
<(eventhandler-declaration-statements)>
ENDCLASS;
The CLASS statement enables you to define attributes, methods, events, and event
handlers for a class and to specify whether the class supports or requires an interface.
The remaining sections in this chapter describe these elements in more detail.
The EXTENDS clause specifies the parent class. If you do not specify an EXTENDS
clause, SCL assumes that sashelp.fsp.object.class is the parent class.
Using the CLASS block instead of the Class Editor to create a class enables the compiler
to detect errors at compile time, which results in improved performance during run time.
For a complete description of the CLASS statement, see “CLASS” on page 249. For a
description of using the Class Editor to define classes, refer to Guide to SAS/AF
Applications Development.
Generating CLASS Entries from CLASS Blocks
Suppose you are editing an SCL entry in the Build window and that the entry contains a
CLASS block. For example:
class Simple extends myParent;
public num num1;
M1: method n:num return=num / (scl='work.a.uSimple.scl');
M2: method return=num;
num1 = 3;
dcl num n = M1(num1);
return (n);
endmethod;
endclass;
To generate a CLASS entry from the CLASS block, issue the SAVECLASS command
or select File ð Save as class.... Generating the CLASS entry from the CLASS block is
equivalent to using the Class Editor to create a CLASS entry interactively.
Generating CLASS Blocks from CLASS Entries
The CLASS block is especially useful when you need to make many changes to an
existing class. To make changes to an existing class, use the CREATESCL function to
write the class definition to an SCL entry. You can then edit the SCL entry in the Build
window. After you finish entering changes, you can generate the CLASS entry by
issuing the SAVECLASS command or selecting File ð Save as class.... For more
information, see “CREATESCL” on page 289.
Referencing Class Methods or Attributes
Any METHOD block in a class can refer to methods or attributes in its own class
without specifying the _SELF_ system variable (which contains the object identifier for
the class). For example, if method M1 is defined in class X (and it returns a value), then
any method in class X can refer to method M1 as follows:
112
Chapter 8
•
SAS Object-Oriented Programming Concepts
n=M1();
You do not need to use the _SELF_ system variable:
n=_SELF_.M1();
Omitting references to the _SELF_ variable (which is referred to as shortcut syntax)
makes programs easier to read and maintain. However, if you are referencing a method
or attribute that is not in the class you are creating, you must specify the object
reference.
Instantiating Classes
To instantiate a class, declare a variable of the specific class type, then use the _NEW_
operator. For example:
dcl mylib.classes.collection.class C1;
C1 = _new_ Collection();
You can combine these two operations as follows:
dcl mylib.classes.collection.class C1 = _new_ Collection();
The _NEW_ operator combines the actions of the LOADCLASS function, which loads a
class, with the _new method, which initializes the object by invoking the object's _init
method.
You can combine the _NEW_ operator with the IMPORT statement, which defines a
search path for references to CLASS entries, so that you can refer to these entries with
one or two-level names instead of having to use a four-level name in each reference.
For example, you can use the following statements to create a new collection object
called C1 as an instance of the collection class that is stored in
mylib.classes.collection.class:
/* Collection class is defined in
*/
/* the catalog MYLIB.MYCAT
*/
import mylib.mycat.collection.class;
/* Create object C1 from a collection class */
/* defined in MYLIB.MYCAT.COLLECTION.CLASS */
declare Collection C1=_new_ Collection();
For more information, see “_NEW_” on page 560 and “LOADCLASS” on page 517.
Methods
Introduction
Methods define the operations that can be executed by any component that you create
from that class. In other words, methods are how classes (and instances of those classes)
do their work.
Methods can be declared in CLASS blocks. To declare a method, include the following
METHOD statement in your CLASS block:
label : <scope> METHOD <parameter-list></(method-options)>;
The statements that implement the method can either follow the declaration, or they can
reside in a separate SCL entry.
Methods
113
Methods are implemented in METHOD blocks. A METHOD block begins with the
METHOD statement, includes the SCL code that implements the method, and then ends
with the ENDMETHOD statement.
label : <scope> METHOD <parameter-list>
<OPTIONAL=parameter-list>
<ARGLIST=parm-list-id |REST=rest-list-id>
RETURN=limited-data-type
</ (method-options)>;
. . . SCL statements that implement the method. . .
ENDMETHOD;
If your program is an object-oriented program, the METHOD blocks are contained either
in the CLASS block or in a USECLASS block that is stored in a separate SCL entry
from the CLASS block. To store the method implementation in a separate SCL entry,
when you declare the method in the CLASS block, you specify (with the SCL=entryname option) the name of another SCL entry that contains the method implementation.
For example, the Add method can be implemented in the CLASS block as follows:
class Arithmetic;
add: method n1 n2:num;
return(n1 + n2);
endmethod;
endclass;
If you want to implement the Add method in a separate SCL entry, then the CLASS
block would contain only the method declaration:
class Arithmetic;
add: method n1 n2:num / (scl='work.a.b.scl');
endclass;
The work.a.b.scl entry would contain a USECLASS block that implements the Add
method:
useclass Arithmetic;
add: method n1 n2: num;
return (n1 + n2);
endmethod;
enduseclass;
See “METHOD (define)” on page 535 for a complete description of implementing
methods with the METHOD statement. For more information about implementing
methods in USECLASS blocks, see
•
“Introduction to SCL Program Structure” on page 9
•
“Implementing Methods Outside of Classes” on page 127
•
“USECLASS” on page 706
Note: The method options that you specify in the CLASS block can also be specified in
the USECLASS block. Any option that is included in the CLASS block and is used
to specify a nondefault value must be repeated in the USECLASS block. For
example, if you specify State='O' or Signature='N' in the CLASS block, then
you must repeat those options in the USECLASS block. However, the SCL option
will be ignored in the USECLASS block.
For compatibility with Version 6, you can also define METHOD blocks in a separate
SCL entry outside of CLASS and USECLASS blocks. However, such an application is
114
Chapter 8
•
SAS Object-Oriented Programming Concepts
not a strictly object-oriented application. For these methods, SCL will not validate
method names and parameter types during compile time. See “Defining and Using
Methods in SCL Programs” on page 13 for more information about methods that are not
declared or implemented within a class.
Defining Method Scope
SCL supports variable method scope, which gives you considerable design flexibility.
Method scope can be defined as Public, Protected, or Private. The default scope is
Public. In order of narrowing scope,
•
Public methods can be accessed by any other class and are inherited by subclasses.
•
Protected methods can be accessed only by the same class and its subclasses; they
are inherited by subclasses.
•
Private methods can be accessed only by the same class and are not inherited by
subclasses.
For example, the Scope class defines two public methods (m1 and m4), one private
method (m2), and one protected method (m3):
class Scope;
m1: public method n:num return=num
/(scl='work.a.uScope.scl');
m2: private method :char;
/(scl='work.b.uScope.scl');
m3: protected method return=num;
num = 3;
dcl num n = m1(num);
return(n);
endmethod;
m4: method
/(scl='work.c.uScope.scl');
endclass;
By default, method m4 is a public method.
Defining Method Names and Labels
Introduction
Method names can be up to 256 characters long. Method labels can be up to 32
characters long. The name of a method should match its label whenever possible.
Note: A method that has the same name as the class that contains it is called a
constructor. See “Defining Constructors” on page 124 for more information.
Specifying a Name That Is Different from the Label
If you need the method name to be different from the method label, you must specify
either the METHOD or LABEL option in the METHOD statement. These options are
mutually exclusive.
Note: In dot notation, always use the method name. When implementing the method,
always use the method label.
For example, a label of MyMethod may be sufficient, but if you want the method name
to be MySortSalaryDataMethod, you can declare the method as follows:
Methods
115
class a;
MyMethod: public method sal:num
/(Method='MySortSalaryDataMethod', SCL='work.a.a.scl');
endclass;
When you implement the method in work.a.a.scl, you identify the method by using
the method label as follows:
useclass a;
MyMethod: public method sal:num;
...SCL statements...
endmethod;
enduseclass;
You would reference this method in dot notation by using the method name as follows:
obj.MySortSalaryDataMethod(n);
Alternatively, you can specify the LABEL option. For example, to specify a method
name of Increase and a method label of CalculatePercentIncrease, you could declare the
method as follows:
class a;
Increase: public method
/(Label='CalculatePercentIncrease', SCL='work.a.b.scl');
endclass;
As in the previous example, you use the method label when you implement the method,
and you use the method name when you refer to the method in dot notation. In
work.a.b.scl, you would implement the method as follows:
useclass a;
CalculatePercentIncrease: public method;
...SCL statements...
endmethod;
enduseclass;
You would reference the method in dot notation as follows:
obj.Increase();
Using Underscores in Method Names
In Version 6, SAS/AF software used underscores to separate words in method names
(for example, _set_background_color_). The current convention is to use a lowercase
letter for the first letter and to subsequently uppercase the first letter of any joined word
(for example, _setBackgroundColor).
The embedded underscores have been removed to promote readability. However, for
compatibility, the compiler recognizes _set_background_color_ as equivalent to
_setBackgroundColor. All Version 6 code that uses the old naming convention in CALL
SEND or CALL NOTIFY method invocations will still function with no modification.
Although it is possible for you to name a new method using a leading underscore, you
should use caution when doing so. Your method names may conflict with future releases
of SAS/AF software if SAS Institute adds new methods to the parent classes.
Specifying Parameter Types and Storage Types
When you define a method parameter, you must specify its data type. Optionally, you
can also specify its storage type: input,update, or output. The storage type determines
how methods can modify each other's parameters:
116
Chapter 8
•
SAS Object-Oriented Programming Concepts
input
The values of the caller's parameters are copied into the corresponding parameters in
the called method. When the called method's ENDMETHOD statement is executed,
any updated values are not copied out to the caller's parameters. This is equivalent to
using CALL NOCHANGE() inside the METHOD block.
update
The values of the caller's parameters are copied into the corresponding parameters in
the called method. When the called method's ENDMETHOD statement is executed,
any updated values are copied out to the caller's parameters (unless CALL
NOCHANGE is specified). An error condition results if the corresponding parameter
in the calling program is a constant, because a constant cannot receive a value. All
Version 6 SCL method parameters are update parameters.
output
This storage type serves as an indication in the code that only the returned value is
significant, despite the fact that the input parameter might change. Functionally, the
output type is the same as the update type.
The default parameter storage type is update.
You use the colon (:) delimiter to specify both the storage type and the data type for each
method parameter:
variables<:storage>:type
In the following example, the TypeStore class defines four methods:
import sashelp.fsp.collection.class;
class TypeStore;
m1: method n:num a b:update:char return=num
/(scl = 'work.a.uType.scl');
m2: method n:output:num c:i:char
/(scl = 'work.b.uType.scl');
m3: method s:i:Collection
/(scl = 'work.c.uType.scl');
m4: method l:o:list
/(scl = 'work.d.uType.scl');
endclass;
The parameter storage type and data type for each method are as follows:
Method
Parameter
Data Type
Storage
m1
n
numeric
update
a
character
update
b
character
update
n
numeric
output
c
character
input
m3
s
Collection class
input
m4
l
list
output
m2
Methods
117
Note: If you specify the storage type for a parameter in the CLASS block, then you
must also specify the storage type in the USECLASS block.
Passing Objects as Arguments for Methods
An object can be declared as an INTRFACE object, a CLASS object, or a generic
OBJECT. If you declare an object as a generic OBJECT, then the compiler cannot
validate attributes or methods for that object. Validation is deferred until run time. Any
error that results from using incorrect methods or attributes for the generic object will
cause the program to halt. For example, if you pass a listbox class to a method that is
expecting a collection object, the program will halt.
Object types are treated internally as numeric values. This can affect how you overload
methods. See “Overloading and List, Object, and Numeric Types” on page 123 for more
information.
Returning Values From Methods
When you declare or implement a method, you can specify the data type of the return
value with the RETURN option. If the method has a RETURN option, then the method
implementation must contain a RETURN statement. The method's RETURN statement
must specify a variable, expression, or value of the same type. In the following example,
method m1 returns a numeric value:
class mylib.mycat.myclass.class;
/* method declaration */
m1: method n:num c:char return=num;
/* method implementation */
return(n+length(c));
endmethod;
endclass;
Method Signatures
Introduction
A method's signature is a set of parameters that uniquely identifies the method to the
SCL compiler. Method signatures enable the compiler to check method parameters at
compile time and can enable your program to run more efficiently. All references to a
method must conform to its signature definition. Overloaded methods must have
signatures. (See “Overloading Methods” on page 120.)
A signature is automatically generated for each SCOM class method unless you specify
Signature='N' in the method's option list. By default, Signature='Y' for all
SCOM class methods. When you edit a class in the Build window, a signature is
generated for each method that is declared in that class when you issue the
SAVECLASS command or select File ð Save as class....
For all Version 6 methods, the default is Signature='N'. See “Converting Version 6
Non-Visual Classes to SCOM Classes” on page 145 for information about adding
signatures to Version 6 methods.
For example, the following method declarations show methods that have different
signatures:
Method1: method name:char
number:num;
118
Chapter 8
•
SAS Object-Oriented Programming Concepts
Method2: method number:num name:char;
Method3: method name:char;
Method4: method return=num;
Each method signature is a unique combination, varying by argument number and type:
•
The first signature contains a character argument and a numeric argument.
•
The second signature contains a numeric argument and a character argument.
•
The third signature contains a single character argument.
•
The fourth signature contains no arguments.
These four method signatures have the following sigstrings (see “Signature Strings
(SIGSTRINGs)” on page 118 ):
Method1
Method2
Method3
Method4
sigstring:
sigstring:
sigstring:
sigstring:
(CN)V
(NC)V
(C)V
()N
The order of arguments also determines the method signature. For example, the
getColNum methods below have different signatures — (CN)V and (NC)V — because
the arguments are reversed. As a result, they are invoked differently, but they return the
same result.
/* method1 */
getColNum: method colname:char number:update:num;
number = getnitemn(listid, colname, 1, 1, 0);
endmethod;
/* method2 */
getColNum: method number:update:num colname:char;
number = getnitemn(listid, colname, 1, 1, 0);
endmethod;
You can also use the Class Editor to define method signatures. See Guide to SAS/AF
Applications Development for more information.
Signature Strings (SIGSTRINGs)
Signatures are usually represented by a shorthand notation, called a sigstring. This
sigstring is stored in the method metadata as SIGSTRING.
A sigstring has the following compressed form:
(<argument-type-1 argument-type-2...argument-type-n>)return-type
Each argument type can be one of the following:
N
Numeric
C
Character string
L
SCL list
O
Generic object
Methods
119
O:<class-name>;
Specific class. The class name should be preceded by O: and followed by a semicolon.
Return-type can be any of the above types, or V for void, which specifies that the method
does not return a value. The return type cannot be an array.
Arrays are shown by preceding any of the above types with a bracket ( [ ). For example,
a method that receives a numeric value and an array of characters and returns a numeric
value would have the signature(N[C)N.
Here are some examples of method signatures:
•
A method that does not receive any parameters and does not return a value: ()V.
This sigstring is the default signature.
•
A method that returns a numeric value and that requires three parameters, numeric,
character, and list: (NCL)N.
•
A method that does not have a return value and that requires an object of type
ProgramHalt and a numeric value:
(O:sashelp.classes.programHalt.class;N)V
•
A method that returns a character value and receives a generic object and a character
value: (OC)C.
Note: Although the return type is listed as part of the sigstring, it is not used by SCL to
identify the method. Therefore, it is recommended that you do not define methods
that differ only in return type. See “Overloading Methods” on page 120 for more
information.
How Signatures Are Used
Signatures are most useful when SCL has to distinguish among the different forms of an
overloaded method. The SCL compiler uses signatures to validate method parameters.
When you execute your program, SCL uses signatures to determine which method to
call.
For example, suppose your program contains the following class:
class Sig;
/* Signature is (N)C */
M1: method n:num return=char /(scl='work.a.uSig.scl');
/* Signature is ([C)V */
M1: private method n(*):char /(scl='work.a.uSig.scl');
/* Signature is ()V */
M1: protected method /(scl='work.a.uSig.scl');
/* Signature is (NC)V
M1: method n:num c:char /(scl='work.a.uSig.scl');
endclass;
Suppose also that your program calls M1 as follows:
dcl char ch;
ch = M1(3);
SCL will call the method with the signature (N)C. If your program calls M1 like this:
M1();
SCL will call the method with the signature ()V.
120
Chapter 8
•
SAS Object-Oriented Programming Concepts
Altering Existing Signatures
After defining a signature for a method and deploying the class that contains it for public
use, you should not alter the signature of the method in future versions of the class.
Doing so could result in program halts for users who have already compiled their
applications. Instead of altering an existing signature, you should overload the method to
use the desired signature, leaving the previous signature intact.
Forward-Referencing Methods
Within a CLASS block, if a method invokes a another method within that same class,
then either the second method must be implemented before the first, or the second
method must be declared with the Forward='Y' option.
Note: Any methods that are forward-referenced must be implemented in the class in
which they are declared.
In the following example, m1 calls m2, so the compiler needs to know the existence of
m2 before it can compile m1.
class mylib.mycat.forward.class;
m2: method n:num c:char return=num / (forward='y');
m1: method n1 n2:num mylist:list return=num;
dcl num listLen = listlen(mylist);
dcl num retVal;
if (listLen = 1) then
retVal=m2(n1,'abc');
else if (listLen = 2) then
retVal=m2(n2,'abc');
endmethod;
m2:method n:num c:char return=num;
return(n+length(c));
endmethod;
endclass;
Overloading Methods
Introduction
You can overload methods only for SCOM classes (classes created using Version 8 or
later). Method overloading is the process of defining multiple methods that have the
same name, but which differ in parameter number, type, or both. Overloading methods
enables you to
•
use the same name for methods that are related conceptually.
•
create methods that have optional parameters.
All overloaded methods must have method signatures because SCL uses the signatures
to differentiate between overloaded methods. If you call an overloaded method, SCL
checks the method arguments, scans the signatures for a match, and executes the
appropriate code. A method that has no signature cannot be overloaded.
If you overload a method, and the signatures differ only in the return type, the results are
unpredictable. The compiler will use the first version of the method that it finds to
validate the method. If the compiler finds the incorrect version, it generates an error. If
your program compiles without errors, then when you run the program, SCL will
execute the first version of the method that it finds. If it finds the incorrect version, SCL
generates an error. If it finds the correct version, your program might run normally.
Methods
121
Each method in a set of overloaded methods can have a different scope, as well.
However, the scope is not considered part of the signature, so you may not define two
methods that differ only by scope. (See “Defining Method Scope” on page 114.)
Example: Different Parameter Types
Suppose you have the following two methods, where each method performs a different
operation on its arguments:
CombineNumerics: public method a :num b :num
return=num;
endmethod;
CombineStrings: public method c :char d :char
return=char;
endmethod;
Assume that CombineNumerics adds the values of A and B, whereas CombineStrings
concatenates the values of C and D. In general terms, these two methods combine two
pieces of data in different ways based on their data types.
Using method overloading, these methods could become
Combine: public method a :num b :num
return=num;
endmethod;
Combine: public method c :char d :char
return=char;
endmethod;
In this case, the Combine method is overloaded with two different parameter lists: one
that takes two numeric values and returns a numeric value, and another that takes two
character parameters and returns a character value.
As a result, you have defined two methods that have the same name but different
parameter types. With this simple change, you do not have to worry about which method
to call. The Combine method can be called with either set of arguments, and SCL will
determine which method is the correct one to use, based on the arguments that are
supplied in the method call. If the arguments are numeric, SCL calls the first version
shown above. If the arguments are character, SCL calls the second version. The caller
can essentially view the two separate methods as one method that can operate on
different types of data.
Here is a more complete example that shows how method overloading fits in with the
class syntax. Suppose you create X.SCL and issue the SAVECLASS command, which
generates the X class. (Although it is true here, it is not necessary that the class name
match the entry name.)
class X;
Combine: public method a:num b:num
dcl num value;
value = a + b;
return value;
endmethod;
return=num;
Combine: public method a:char b:char return=char;
dcl char value;
value = a || b;
return value;
endmethod;
122
Chapter 8
•
SAS Object-Oriented Programming Concepts
endclass;
You can then create another entry, Y.SCL. When you compile and execute Y.SCL, it
instantiates the X class and calls each of the Combine methods.
import
init:
dcl
dcl
dcl
n =
c =
put
X.class;
num n;
char c;
X xobject = _new_ X();
xobject.Combine(1,2);
xobject.Combine("abc","def");
n= c=;
The PUT statement produces
n=3 c=abcdef
Example: Different Numbers of Parameters
Another typical use of method overloading is to create methods that have optional
parameters.
Note: This example shows two implementations of an overloaded method that each
accept different numbers of parameters. “Defining One Implementation That
Accepts Optional Parameters” on page 123 describes how to use the OPTIONAL
option to create a method with one implementation that accepts different numbers of
parameters.
For example, suppose we have a method that takes a character string and a numeric
value, where the numeric value is used as a flag to indicate a particular action. The
method signature would be (CN)V.
M: public method c :char f :num;
if (f = 1) then
/* something */
else if (f = 2)
/* something else */
else
/* another thing */
endmethod;
If method M is usually called with the flag equal to one, you can overload M as (C)V,
where that method would simply include a call to the original M. The flag becomes an
optional parameter.
M:
public method c: char;
M(c, 1);
endmethod;
When you want the flag to be equal to one, call M with only a character string
parameter. Notice that this is not an error. Method M can be called with either a single
character string, or with a character string and a numeric — this is the essence of method
overloading. Also, the call M(c,1); is not a recursive call with an incorrect parameter
list. It is a call to the original method M.
This example can also be turned around for cases with existing code. Assume that we
originally had the method M with signature (C)V and that it did all the work.
M: public method c: char;
/* A lot of code for processing C. */
Methods
123
endmethod;
Suppose you wanted to add an optional flag parameter, but did not want to change the
(possibly many) existing calls to M. All you need to do is overload M with (CN)V and
write the methods as follows:
M:
public method c: char f: num;
Common(c, f);
endmethod;
M:
public method c: char;
Common(c, 0);
endmethod;
Common: public method c: char f: num;
if (f) then
/* Do something extra. */
/* Fall through to same old code for */
/* processing S.
*/
endmethod;
Notice that when you call M with a single character string, you get the old behavior.
When you call M with a string and a (non-zero) flag parameter, you get the optional
behavior.
Defining One Implementation That Accepts Optional Parameters
You can use the OPTIONAL option to create an overloaded method with only one
implementation that will accept different numbers of parameters, depending on which
arguments are passed to it.
In the following example, the method M1 will accept from two to four parameters:
class a;
M1: public method p1:input:num p2:output:char
optional=p3:num p4:char
/ (scl='mylib.classes.old.scl');
endclass;
SCL will generate three signatures for this method:
•
(NC)V
•
(NCN)V
•
(NCNC)V
Overloading and List, Object, and Numeric Types
Lists and objects (variables declared with either the OBJECT keyword or a specific class
name) are treated internally as Numeric values. As a result, in certain situations,
variables of type List, Numeric, generic Object, and specific class names are
interchangeable. For example, you can assign a generic Object or List to a variable that
has been declared as Numeric, or you can assign a generic Object to a List. This
flexibility enables Version 6 programs in which list identifiers are stored as Numeric
variables to remain compatible with SCOM classes.
The equivalence between objects, lists, and numeric variables requires that you exercise
caution when overloading methods with these types of parameters. When attempting to
match a method signature, the compiler first attempts to find the best possible match by
matching the most parameter types exactly. If no exact match can be found, the compiler
resorts to using the equivalence between List, generic Object, and Numeric types.
124
Chapter 8
•
SAS Object-Oriented Programming Concepts
For example, suppose you have a method M with a single signature (L)V. If you pass a
numeric value, a list, or an object, it will be matched, and method M will be called. If
you overload M with signature (N)V, then Numeric values will match the signature
(N)V, and List values will match the signature (L)V. However, List values that are
undeclared or declared as Numeric will now match the wrong method. Therefore, you
must explicitly declare them with the LIST keyword to make this example work
correctly. Also, if you pass an object, it will match both (L)V and (N)V, so the compiler
cannot determine which method to call and will generate an error message.
Overriding Existing Methods
When you instantiate a class, the new class (or subclass) inherits the methods of the
parent class. If you want to use the signature of one of the parent's methods, but you
want to replace the implementation with your own implementation, you can override the
parent's method. To override the implementation of a method, specify State='O' in
the method declaration and in the method implementation. Here is an example for a class
named State:
class State;
_init: method / (state='o');
_super();
endmethod;
endclass;
If the method you are overriding has no signature, be sure to specify signature='N'
on the overriding method. For example:
class State2;
_init: method / (state='o', signature='N');
_super();
endmethod;
endclass;
Defining Constructors
Introduction
Constructors are methods that are used to initialize an instance of a class. The Object
class provides a default constructor that is inherited for all classes. Unless your class
requires special initialization, you do not need to create a constructor.
Each constructor has the following characteristics:
•
It has the same name as the class in which it is declared.
•
It is run automatically when the class is instantiated with the _NEW_ operator. If you
do not create your own constructor, the default constructor is executed.
Note: Using the _NEW_ operator to instantiate a class is the only way to run
constructors. Unlike other user-defined methods, you cannot execute constructors
using dot notation. If you instantiate a class in any way other than by using the
_NEW_ operator (for example, with the _NEO_ operator), constructors are not
executed.
•
It is intended to run as an initializer for the instance. Therefore, only constructors can
call other constructors. A constructor cannot be called from a method that is not a
constructor.
Methods
•
125
It cannot return a value; it must be void a method. The _NEW_ operator returns the
value for the new instance of the class; it cannot return a value from an implicitly
called constructor.
For example, you could define a constructor X for class X as follows:
class X;
X: method n: num;
put 'In constructor, n=';
endmethod;
endclass;
You can instantiate the class as follows:
init:
dcl X x = _new_ X(99);
return;
The constructor is run automatically when the class is instantiated. The argument to
_NEW_, 99, is passed to the constructor. The output is
In constructor, n=99
Overloading Constructors
Like other methods, constructors can be overloaded. Any void method that has the same
name as the class is treated as a constructor. The _NEW_ operator determines which
constructor to call based on the arguments that are passed to it. For example, the
Complex class defines two constructors. The first constructor initializes a complex
number with an ordered pair of real numbers. The second constructor initializes a
complex number with another complex number.
class Complex;
private num a b;
Complex: method r1: num r2: num;
a = r1;
b = r2;
endmethod;
Complex: method c: complex;
a = c.a;
b = c.b;
endmethod;
endclass;
This class can be instantiated with either of the following statements:
dcl Complex c = _new_(1,2);
dcl Complex c2 = _new_(c);
These statements both create complex numbers. Both numbers are equal to 1 + 2i.
Overriding the Default Constructor
The default constructor does not take any arguments. If you want to create your own
constructor that does not take any arguments, you must explicitly override the default
constructor. To override the default constructor, specify State='o' in the method
options list.
class X;
X: method /(state='o');
126
Chapter 8
•
SAS Object-Oriented Programming Concepts
...SCL statements to initialize class X...
endmethod;
endclass;
Calling Constructors Explicitly
Constructors can be called explicitly only from other constructors. The _NEW_ operator
calls the first constructor. The first constructor can call the second constructor, and so
on.
When a constructor calls another constructor within the same class, it must use the
_SELF_ system variable. For example, you could overload X as follows:
class X;
private num m;
X: method n: num;
_self_(n, 1);
endmethod;
X: method n1: num n2: num;
m = n1 + n2;
endmethod;
endclass;
The first constructor, which takes one argument, calls the second constructor, which
takes two arguments, and passes in the constant 1 for the second argument.
The following labeled section creates two instances of X. In the first instance, the m
attribute is set to 3. In the second instance, the m attribute is set to 100.
init:
dcl X x = _new_ X(1,2);
dcl X x2 = _new_ X(99);
return;
Constructors can call parent constructors by using the _SUPER operator. For example,
suppose you define class X as follows:
class X;
protected num m;
X: method n: num;
m = n * 2;
endmethod;
endclass;
Then, you create a subclass Y whose parent class is X. The constructor for Y overrides
the default constructor for Y and calls the constructor for its parent class, X.
class Y extends X;
public num p;
Y: method n: num /(state='o');
_super(n);
p = m - 1;
endmethod;
endclass;
Methods
127
You can instantiate Y as shown in the following labeled section. In this example, the
constructor in Y is called with argument 10. This value is passed to the constructor in X,
which uses it to initialize the m attribute to 20. Y then initializes the p attribute to 19.
init:
dcl Y y = _new_ Y(10);
put y.p=;
return;
The output would be:
y.p=19
Note: As with other overridden methods that have identical signatures, you must
explicitly override the constructor in Y because there is a constructor in X that has
the same signature.
Specifying That a Method Is Not a Constructor
The compiler automatically treats as a constructor any void method that has the same
name as the class. If you do not want such a method to be treated as a constructor, you
can specify constructor='n' in the method declaration.
class X;
X: method /(constructor='n');
put 'Is not constructor';
endmethod;
endclass;
init:
dcl X x = _new_ X();
put 'After constructor';
x.x();
return;
This will result in the following output:
After constructor
Is not constructor
Implementing Methods Outside of Classes
You can define the implementation of methods outside the SCL entry that contains the
CLASS block that defines the class. This feature enables multiple people to work on
class methods simultaneously.
To define class methods in a different SCL entry, use the USECLASS statement block.
The USECLASS block binds methods that it contains to the class that is specified in the
USECLASS statement. The USECLASS statement also enables you to define
implementations for overloading methods. (See “Overloading Methods” on page 120. )
Method implementations inside a USECLASS block can include any SCL functions and
routines. However, the only SCL statements that are allowed in USECLASS blocks are
METHOD statements.
The USECLASS block binds the methods that it contains to a class that is defined in a
CLASS statement block or in the Class Editor. Therefore, all references to the methods
and the attributes of the class can bypass references to the _SELF_ variable completely
as long as no ambiguity problem is created. Because the binding occurs at compile time,
128
Chapter 8
•
SAS Object-Oriented Programming Concepts
the SCL compiler can detect whether an undefined variable is a local variable or a class
attribute. See also “Referencing Class Methods or Attributes” on page 111.
Method Metadata
SCL stores metadata for maintaining and executing methods. You can query a class (or a
method within a class) to view the method metadata. For example, to list the metadata
for a specific method, execute code similar to the following:
init:
DCL num rc metadata;
DCL object obj;
obj=loadclass('class-name');
/* metadata is a numeric list identifier */
rc=obj._getMethod('getMaxNum',metadata);
call putlist(metadata,'',2);
return;
Attributes
Introduction
Attributes are the properties that specify the information associated with a component,
such as its name, description, and color. Attributes determine how a component will look
and behave. For example, the Push Button Control has an attribute named label that
specifies the text displayed on the button. You can create two instances of the Push
Button Control on your frame and have one display “OK” and the other display
“Cancel,” simply by specifying a different value for the label attribute of each
instance.
You can define attributes with attribute statements in CLASS blocks:
scope data-type attribute-name/(attribute-options);
Attribute names can be up to 256 characters long.
Like methods, attributes can have public, private, or protected scope. The scope works
the same for attributes as it does for methods. See “Defining Method Scope” on page
114 for more information.
Examples of attribute options include the attribute description, whether the attribute is
editable or linkable, custom access methods that are to be executed when the attribute is
queried or set, and whether the attribute sends events.
If an attribute is editable, you can use the Editor option to specify the name of the
FRAME, SCL, or PROGRAM entry that will be used to edit the attribute's value. This
entry is displayed and executed by the Properties window when the ellipsis button (...) is
selected.
To specify an attribute's category, use the Category attribute option. The category is used
for grouping similar types of options in the Class Editor or for displaying related
attributes in the Properties window. You can create your own category names.
Components that are supplied by SAS may belong to predefined categories.
Attributes 129
Creating Attributes Automatically
With the Autocreate option, you can control whether storage for list attributes and class
attributes is automatically created when you instantiate a class. By default,
Autocreate='Y', which means that SCL automatically uses the _NEW_ operator to
instantiate class attributes and calls the MAKELIST function to create the list attributes.
Note: Even when Autocreate='Y', storage is not created for generic objects because
the specific class is unknown.
If you specify Autocreate='N', then storage is not automatically created, and it is
your responsibility to create (and later destroy) any list attributes or class attributes after
the class is instantiated.
import sashelp.fsp.collection.class;
class myAttr;
public list myList / (autocreate='N');
public list listTwo;
/* created automatically */
public collection c1; /* created automatically */
public collection c2 / (autocreate='N');
endclass;
Specifying Where an Attribute Value Can Be Changed
An attribute's scope and the value of its Editable option determines which methods can
change an attribute's value.
•
If the scope is public and Editable='Y', then the attribute can be accessed (both
queried and set) from any class method as well as from a frame SCL program.
•
If the scope is public and Editable='N', then the attribute can only be queried
from any class method or frame SCL program. However, only the class or subclasses
of the class can modify the attribute value.
•
If the scope is protected and Editable='N', then the class and its subclasses can
query the attribute value, but only the class itself can set or change the value. A
frame SCL program cannot set or query the value.
•
If the scope is private and Editable='N', then the attribute value can be queried
only from methods in the class on which it is defined, but it cannot be set by the
class. Subclasses cannot access these attributes, nor can a frame SCL program. This
combination of settings creates a private, pre-initialized, read-only constant.
Setting Initial Values and the List of Valid Values
Unless you specify otherwise, all numeric attributes are initialized to missing values, and
all character attributes are initialized to blank strings. You can use the initialValue
attribute option to explicitly initialize an attribute. For example:
class myAttr;
public num n1 / (initialvalue = 3);
public list list2 / (initialvalue = {1, 2, 'abc', 'def'};
endclass;
Explicitly initializing attribute values improves the performance of your program.
130
Chapter 8
•
SAS Object-Oriented Programming Concepts
You can use the ValidValues attribute option to specify a list of values that the attribute
can have. This list is used as part of the validation process that occurs when the value is
set programmatically by using either dot notation or the _setAttributeValue method.
If you specify the ValidValues option and the InitialValue option, the value that you
specify with the InitialValue option must be included in the values that you specify with
the ValidValues option.
In the list of valid values, you can use blanks to separate values, or, if the values
themselves contain blanks, use a comma or a slash (/) as the separator. For example:
class business_graph_c;
public char statistic
/ (ValidValues='Frequency/Mean/Cumulative Percent',
InitialValue='Mean');
public char highlightEnabled
/ (ValidValues='Yes No',
InitialValue='Yes');
endclass;
You can also specify an SCL or SLIST entry to validate values. For more information on
how to use an SCL entry to perform validation, refer toGuide to SAS/AF Applications
Development.
Associating Custom Access Methods with Attributes
A custom access method (CAM) is a method that is executed automatically when an
attribute's value is queried or set using dot notation. When you query the value of an
attribute, SCL calls the _getAttributeValue method. When you set the value of an
attribute, SCL calls the _setAttributeValue method. These methods are inherited from
the Object class.
You can use the getCAM and setCAM attribute options to specify additional methods
that you want _getAttributeValue or _setAttributeValue to execute. For example:
class CAM;
public char A / (getCAM='M1');
public num B / (setCAM='M2');
protected M1: method c:char;
put 'In M1';
endmethod;
protected M2: method b:num;
put 'In M2';
endmethod;
endclass;
When the value of A is queried, _getAttributeValue is called, then M1 is executed.
When the value of B is set, _setAttributeValue is called, then M2 is executed.
CAMs always have a single signature and cannot be overloaded. The CAM signature
contains a single parameter that is the same type as its associated attribute.
A CAM always returns a numeric value. If the returned value = 0, the CAM executed
successfully. A non-zero value indicates failure.
You should never call a CAM directly; instead, use the _getAttributeValue or
_setAttributeValue methods to call it automatically. To prevent CAMs from being called
directly, it is recommended that you define them as protected methods.
Attributes 131
Linking Attributes
Attribute linking enables one component to automatically update the value of one of its
attributes when the value of another component attribute is changed. You can link
attributes between components or within the same component. Only public attributes are
linkable.
To implement attribute linking, you need to identify attributes as either source attributes
or target attributes. You can identify source and target attributes either in the Properties
window or with SCL. To identify an attribute as a source attribute with SCL, specify
SendEvent='Y' in the attribute's option list. To identity an attribute as a target
attribute, specify Linkable='Y' in the attribute's option list.
You can then link the attributes (specify the LinkTo option) in the Properties window.
When SendEvent='Y', SAS/AF software registers an event on the component. For
example, the textColor attribute has an associated event named “textColor Changed”.
You can then register an event handler to trap the event and to conditionally execute
code when the value of the attribute changes.
If you change the SendEvent value from 'Y' to 'N', and if Linkable='Y', then
you must send the “attributeName Changed” event programmatically with the attribute's
setCAM in order for attributes that are linked to this attribute to receive notification that
the value has changed. If the linked attributes do not receive this event, attribute linking
will not work correctly. In the previous example, the setCAM for the textColor
attribute would use the _sendEvent method to send the “textColor Changed” event.
Refer to Guide to SAS/AF Applications Development for more information on attribute
linking.
Attribute Metadata
SCL uses a set of attribute metadata to maintain and manipulate attributes. This metadata
exists as a list that is stored with the class. You can query a class (or an attribute within a
class) with specific methods to view attribute metadata. To list the metadata for a
specific attribute, execute code similar to the following:
init:
DCL num rc;
DCL list metadata;
DCL object obj;
obj=loadclass('class-name');
rc=obj._getAttribute('attribute-name',metadata);
call putlist(metadata,'',3);
return;
132
Chapter 8
•
SAS Object-Oriented Programming Concepts
Accessing Object Attributes and Methods with
Dot Notation
Introduction
SCL provides dot notation for directly accessing object attributes and for invoking
methods instead of using the SEND and NOTIFY routines. Thus, dot notation provides a
shortcut for invoking methods and for setting or querying attribute values. Using dot
notation reduces typing and makes SCL programs easier to read.
Using dot notation enhances run-time performance if you declare the object used in the
dot notation as an instance of a predefined class instead of declaring it as a generic
object. The object's class definition is then known at compile time, enabling the SCL
compiler to verify the method and to access attributes at that time. Moreover, since dot
notation checks the method signature, it is the only way to access an overloaded method.
SEND does not check method signatures. It executes the first name-matched method,
and the program might halt if the method signature does not match.
Syntax
Introduction
The syntax for dot notation is as follows:
object.attribute
or
object.method(<arguments>)
Where
object
specifies an object or an automatic system variable (for example, _SELF_). An
object must be a component in a FRAME entry or a variable that is declared as an
Object type in the SCL program. Automatic system variables like _SELF_ are
declared internally as Object type, so they do not have to be declared explicitly as
such in a program.
attribute
specifies an object attribute to assign or query. It can be of any data type, including
Array. If the attribute is an array, use the following syntax to reference its elements:
object.attributeArray[i]
You can also use parentheses instead of brackets or braces when referencing the
array elements. However, if you have declared the object as a generic object, the
compiler interprets it as a method name rather than an attribute array. If you have
declared a type for the object, and an attribute and method have the same name, the
compiler still interprets the object as a method. To avoid this ambiguity, use brackets
when referencing attribute array elements.
method
specifies the name of the method to invoke. If an object is declared with a specific
class definition, the compiler can perform error checking on the object's method
invocations.
Accessing Object Attributes and Methods with Dot Notation
133
If the object was declared as a generic object (with the OBJECT keyword), then the
method lookup is deferred until run time. If there is no such method for the object,
the program halts. If you declare the object with a specific definition, errors such as
this are discovered at compile time instead of at run time.
arguments
are the arguments passed to the method. Enclose the arguments in parentheses. The
parentheses are required whether or not the method needs any arguments.
You can use dot notation to specify parameters to methods. For example: returnvalue = object.method (object.id);However, if you use dot notation to
specify an update or output parameter, then SCL executes the _setAttributeValue
method, which may produce side effects. See “What Happens When Attribute
Values Are Set or Queried” on page 135 for more information.
Some methods may be defined to return a value of any SCL type. You can access this
returned value by specifying a variable in the left side of the dot notation. For example:
return-value = object.method (<arguments>);
or
if ( object.method (<arguments>) ) then ...
The return value's type defaults to Numeric if it is not explicitly declared. If the declared
type does not match the returned type, and the method signature is known at compile
time, the compiler returns an error. Otherwise, a data conversion might take place, or the
program will halt at run time.
If you override an object's INIT method, you must call _SUPER._INIT before you can
use dot notation to set attribute values or to make other method calls.
Dot notation is not available in the INPUT and PUT functions.
By default, your application halts execution if an error is detected in the dot notation that
is used in the application. You can control this behavior with the
HALTONDOTATTRIBUTE or NOHALTONDOTATTRIBUTE option in the
CONTROL statement. See “CONTROL” on page 274 for more information.
Using Nested Dot Notation
You can also use dot notation in nested form. For example,
value = object.attribute1.method1().attribute2;
is equivalent to the following:
dcl object object1 object2;
object1 = object.attribute1;
/* attribute1 in object
is of OBJECT type */
object2 = object1.method1(); /* method1 in object1
returns an object */
value
= object2.attribute2; /* assign the value of
attribute2 in object2
to the variable
'value'. */
You can also specify the nested dot notation as an l-value. For example,
object.attribute1.method1().attribute2 = value;
is equivalent to the following:
dcl object object1 object2;
134
Chapter 8
•
SAS Object-Oriented Programming Concepts
object1 = object.attribute1;
object2 = object1.method1();
object2.attribute2 = value; /* assume 'value' has
been initialized.
This would set
attribute2 in object2
to the value */
Note: You cannot use nested dot notation inside SUBMIT blocks.
Examples
An application window contains a text entry control named clientName. The following
examples show how to use dot notation to invoke methods and to query and assign
attribute values. For example, the following statement uses dot notation to invoke the
_gray method of the control:
clientName._gray();
This is equivalent to
call send('clientName','_gray');
You can change the text color to blue, using dot notation to set the value of its
textColor attribute:
name.textColor='blue';
You can also use dot notation to query the value of an attribute. For example:
color=clientName.textColor;
You can use dot notation in expressions. You can use a method in an expression only if
the method can return a value via a RETURN statement in its definition. For example,
suppose you create a setTable method, which is a public method and accepts an input
character argument (the name of a SAS table). The method determines whether a SAS
table exists and uses the RETURN statement to pass the return code from the EXIST
function.
setTable: public method dsname:i:char(41) return=num;
rc = exist(dsname, 'DATA');
return rc;
endmethod;
Then you could use a statement like the following to perform actions that depend on the
value that the setTable method returned.
if (obj.setTable('sasuser.houses')) then
/* the table exists, perform an action */
else
/* the table doesn't exist,
*/
/* perform another action
*/
The next example shows how to use dot notation with an object that you create in an
SCL program. Suppose class X is saved in the entry X.SCL, and the INIT section is
saved in the entry Y.SCL.
class x;
public num n;
m: public method n1: num n2: num return=num;
dcl num r;
r = n1 + n2;
Accessing Object Attributes and Methods with Dot Notation
135
/* return sum of n1 and n2 */
return r;
endmethod;
m: public method c1: char c2:char return=char;
dcl num s;
/* concatenate c1 and c2 */
s = c1 || c2;
return s;
endmethod;
endclass;
init:
dcl x xobj = _new_ x();
dcl num n;
dcl string s;
n = xobj.m(99,1);
s = xobj.m("abc","def");
put n= s=;
return;
If you compile and run Y.SCL, it produces
n=100 s=abcdef
What Happens When Attribute Values Are Set or Queried
Introduction
When you use dot notation to change or query an attribute value, SCL translates the
statement to a _setAttributeValue method call (to change the value) or to a
_getAttributeValue method call (to query the value). As a result, defining the attribute
with a getCAM or setCAM method could produce side effects.
When you use dot notation to specify a parameter to a method, SCL executes the
_setAttributeValue method if the parameter is an update or output parameter. SCL
executes the _getAttributeValue method if the parameter is an input parameter.
However, if the object is declared as a generic object or if the method does not have a
signature, then all of the method's parameters are treated as update parameters.
Therefore, SCL will execute the _setAttributeValue method even if the parameter is an
input parameter, which could execute a setCAM method and send an event.
Note: If you use dot notation to access a class attribute, program execution halts if any
error is detected while the _getAttributeValue or _setAttributeValue method is
running. Explicitly invoking the _getAttributeValue or _setAttributeValue method
allows the program to control the halt behavior. The _getAttributeValue or
_setAttributeValue method also enables you to check the return code from the
method. For example:
rc = obj._setAttributeValue ('abc');
if ( rc ) then do;
/* error detected in the _setAttributeValue method */
...more SCL statements...
end;
Setting Attribute Values
When you use dot notation to set the value of an attribute, SCL follows these steps:
136
Chapter 8
•
SAS Object-Oriented Programming Concepts
1. Verify that the attribute exists.
2. Verify that the type of the attribute matches the type of the value that is being set.
3. Check whether the attribute value is in the ValidValues list. If the ValidValues
metadata is an SCL entry, it is executed first to get the list of values to check the
attribute value against.
4. Run the setCAM method, if it is defined, which gives users a chance to perform
additional validation and to process their own side effects.
Note: If the Editable metadata is set to No, the custom set method is not called (even
if it was defined for the attribute).
5. Store the object's value in the attribute.
6. Send the “attributeName Changed” event if the SendEvent metadata is set to Yes.
7. sends the “contents Updated” event if the attribute is specified in the object's
contentsUpdatedAttributes attribute. This event notifies components in a
model/view relationship that a key attribute has been changed.
Accessing Object Attributes and Methods with Dot Notation
Figure 8.2
137
Flow of Control for _setAttributeValue
_setAttributeValue
executes
If attribute is
defined and is not accessed
outside its defined
scope
If attribute type is matched
If EDITABLE
attribute metadata item
= 'Yes'
If specified
VALID VALUES metadata
is working and exists
in the list
If no
No
rc=2; processing ends;
errorMessage attribute is set
No
rc=3; processing ends;
errorMessage attribute is set
No
rc=5; processing ends;
errorMessage attribute is set
rc=4;
errorMessage attribute is set
No
If setCAM exists
setCAM
executes
If setCAM
fails to execute
If
setCAM return
code <=0
No
No
If rc=0
rc=7; processing ends;
errorMessage attribute is set
rc=4 if CAM rc=4, otherwise,
rc=7; processing ends;
errorMessage attribute is set
processing ends
RC (Return Code) Key
Attribute value is set
If SENDEVENT
attribute metadata
item = 'Yes'
_setAttributeValue checks the
contentsUpdatedAttributes attribute and sends
the 'contents updated' event if the attribute is listed
rc=0
Object region is refreshed
Reserved for warning conditions returned from CAMs
successful
1
unsuccessful (an error condition); you can use the
return code to identify an error condition from a
Custom Access Method
2
attribute does not exist on the specified object or
cannot be accessed
3
type mismatch; the type of the passed value does not
match the value of the attribute you are trying to set
4
value passed to _setAttributeValue is not on attribute's
VALIDVALUES list or is otherwise invalid
5
cannot set attribute because its EDITABLE metadata
item is set to 'No.'
7
the Custom Access Method (CAM) failed to run
No
'attribute Name Changed'
event is sent
If object is a
visual control and it
is build time
<0
0
No
rc=0; processing ends
138
Chapter 8
•
SAS Object-Oriented Programming Concepts
Querying Attribute Values
When you use dot notation to query the value of an attribute, SCL follows these steps:
1. Execute the getCAM method to determine the attribute value, if a getCAM method
has been defined.
2. Return the attribute value, if a value has been set.
3. Return the initial class value, if no attribute value has been set.
The following figure shows this process in detail.
Figure 8.3 Flow of Control for _getAttributeValue
_getAttributeValue
executes
If attribute is
defined and not accessed
outside its defined
scope
If attribute type
is matched
If no
No
No
rc=2; processing ends
rc=3; processing ends
If getCAM
is defined
getCAM
executes
No
rc=7; processing ends
Attribute value is returned
rc is propagated as the value
for the 2nd argument on the
_getAttributeValue call
Events and Event Handlers
Introduction
Events alert applications when there is a change of state. Events occur when a user
action takes place (such as a mouse click), when an attribute value is changed, or when a
user-defined condition occurs. Events are essentially generic messages that are sent to
Events and Event Handlers
139
objects from the system or from SCL applications. These messages usually direct an
object to perform some action such as running a method.
Event handlers are methods that listen for these messages and respond to them.
Essentially, an event handler is a method that determines which method to execute after
the event occurs.
SCL supports both system events and user-defined events.
System Events
System events include user interface events (such as mouse clicks) as well as “attribute
changed” events that occur when an attribute value is updated. SCL automatically
defines system events for component attributes when those attributes are declared.
SCL can also automatically send system events for you when a component's attribute is
changed. If you want “attribute changed” events to be sent automatically, specify
SendEvent='Y' in the options list for the attribute.
If you want an action to be performed when the system event occurs, then you need to
define the event handler that you want to be executed when the event occurs. You define
event handlers for system events in the same way that you define them for user-defined
events. See “Defining Event Handlers” on page 139 for more information.
Defining and Sending Events
You can create user-defined events through the Properties window in the Class Editor or
with event declaration statements in CLASS blocks.
EVENT event-name</(event-options)>;
Event names can be up to 256 characters long.
For the event options, you can specify the name of the method that handles the event and
when an object should send the event. Events can be sent automatically either before
(specify Send='Before') or after (Send='After') a method executes or they can be
programmed manually ('Manual') with SCL. New events default to 'After'. You
must specify a method name for events that are to be sent automatically.
After an event is defined, you can use the _sendEvent method to send the event:
object._sendEvent("event-name"<, event-handler-parameters>);
For a complete description of _sendEvent, refer to the SAS/AF online Help.
Defining Event Handlers
You can define event handlers with event handler declaration statements in CLASS
blocks.
EVENTHANDLER event-handler-name</(event-handler-options)>;
As part of the event handler options, you can specify the name of the event, the name of
the method that handles the event, and the name of the object that generates the event
(the sender). As the sender, you can specify '_SELF_' or '_ALL_'. When
Sender='_SELF_', the event handler listens only to events from the class itself. When
Sender='_ALL_', the event handler listens to events from any other class.
140
Chapter 8
•
SAS Object-Oriented Programming Concepts
Using the _addEventHandler method, you can dynamically add a sender to trigger the
event. For a complete description of _addEventHandler, refer to the SAS/AF online
Help.
For more information about defining event handlers, see “CLASS” on page 249.
Example
This example demonstrates how to define and use events and event handlers.
This example creates two classes. The first class defines one event, three event handlers,
and the three methods that those handlers call. The second class defines one event
handler that listens for the event from the first class, and also defines a method to
execute when that event occurs. Lastly, there is separate code that exercises the events
and event handlers in the two classes. It is assumed that both classes are stored in
work.a.
The first class, EHclass1, defines a numerical attribute n, the event myEvent, and the
event handler for this event, M2. When this class is instantiated, the system event name
“n Changed” is automatically assigned to the attribute n and is registered with EHclass1.
When the value of the attribute n is changed, the system automatically sends the “n
Changed” event, and method M1 is executed.
Event handlers M2 and M3 and the corresponding methods are to demonstrate the
response to the _sendEvent method, explained later in this example.
The methods are not defined in sequential order to help demonstrate that the order of
definition has nothing to do with the order of execution.
class EHclass1;
public num n;
/* An attribute with a system event. */
event 'myEvent' / (method='M2');
eventhandler M1 / (sender = '_SELF_', event = 'n Changed');
eventhandler M3 / (sender = '*', event='myEvent');
eventhandler M2 / (sender = '_SELF_', event = 'myEvent');
M1: method a:list;
put "M1: Event is triggered by changing attribute n.";
endmethod;
M3: method;
put "M3: Event is triggered by _sendEvent / sender=*.";
endmethod;
M2: method;
put "M2: Event is triggered by _sendEvent /sender=SELF.";
endmethod;
endclass;
The second class, EHclass2, defines the event handler and corresponding method, M4,
that is also executed when myEvent is sent.
class EHclass2;
/* Sender='*' means that the sender is determined at run time.
eventhandler M4 / (sender = '*', event='myEvent');
*/
Events and Event Handlers
141
M4: method;
put "M4: Event myEvent is defined on another class";
put "
that is triggered by _sendEvent / sender=*.";
endmethod;
endclass;
The following code uses the two classes. The system event “n Changed” is triggered
when the value of the n attribute is modified. The user-defined event myEvent is
triggered with the _sendEvent method.
import work.a.EHclass1.class;
import work.a.EHclass2.class;
init:
/* Reverse the order of these two declarations to */
/* change the order of execution for '*' sender. */
dcl EHclass1 obj1 = _new_ EHclass1();
dcl EHclass2 obj2 = _new_ EHclass2();
/* Trigger the system event. */
obj1.n = 3;
/* Trigger the user-defined event. */
obj1._sendEvent("myEvent");
return;
The order in which the event handlers for myEvent are executed is determined by the
sender of the message. If the sender is _SELF_, the handling class, in this case EHclass1,
has priority, and executes its method first.
If the sender is *, the handlers are executed in the order in which their defining classes
were instantiated; the execution order is not defined by the order of the class definitions
or method definitions.
In this example, M1 is executed first when the "n changed" event occurs. Event handler
M2 is triggered by events from _SELF_, so when myEvent is sent, event handler M2 is
executed first, followed by the event handler M3.
M4 is executed after M3 because M3 is on EHclass1, which was instantiate first.
Reverse the order of the declarations of EHclass1 and EHclass2 to change the order in
which M3 and M4 are executed.
As written above, without the reversed declarations, the output is:
M1:
M2:
M3:
M4:
Event is triggered by changing attribute n.
Event is triggered by _sendEvent / sender=SELF.
Event is triggered by _sendEvent / sender=*.
Event myEvent is defined on another class
that is triggered by _sendEvent / sender=*.
Event and Event Handler Metadata
Events and event handlers are implemented and maintained with metadata. This
metadata exists as a list that is stored with the class. You can query a class (or an event
within a class) to view the event and event handler metadata. To list the metadata for an
event, execute code similar to the following:
init:
142
Chapter 8
•
SAS Object-Oriented Programming Concepts
DCL num rc;
DCL list metadata;
DCL object obj;
obj=loadclass('class-name');
rc=obj._getEvent('event-name', metadata);
call putlist(metadata, '', 3);
rc=obj._getEventHandler('_self_', 'event-handler-name', '_refresh', metadata);
call putlist(metadata, '', 3);
return;
Interfaces
Introduction
Interfaces are groups of method declarations that enable classes to possess a common set
of methods even if the classes are not related hierarchically. An interface is similar to a
class that contains only method declarations.
A class can either support or require an interface. A class that supports an interface must
implement all of the methods in the interface. A class that requires an interface can
invoke any of the methods in the interface.
Suppose you have the following interface:
interface I1;
M1: method;
endinterface;
If class A supports the interface, then it must implement the method M1:
class A supports I1;
M1: method;
put 'Implementation of M1';
endmethod;
endclass;
Class B requires the interface, which means that it can invoke the methods declared in
the interface.
class B requires I1;
M2: method;
dcl I1 myObj = _new_ I1;
myObj.M1();
endmethod;
endclass;
Interfaces are especially useful when you have several unrelated classes that perform a
similar set of actions. These actions can be declared as methods in an interface, and each
class that supports the interface provides its own implementation for each of the
methods. In this way, interfaces provide a form of multiple inheritance.
A class can be defined to support or require one or more interfaces. If two components
share an interface, they can indirectly call each others' methods via that interface. For
example, model/view component communication is implemented with the use of
interfaces. The model typically supports the interface, whereas the view requires the
Interfaces
143
same interface. The interfaces for the components must match before a model/view
relationship can be established. A class stores interface information as a property to
identify whether it supports or requires an interface. Refer to Guide to SAS/AF
Applications Development for more information about model/view communication.
Although classes that support or require an interface are often used together, they are
still independent components and can be used without taking advantage of an interface.
Defining Interfaces
You define interfaces with the INTERFACE statement block:
INTERFACE interface-name<EXTENDS interface-name></ (interface-optional-clause)>;
<limited-method-declaration-statements>
ENDINTERFACE;
For more information about defining interfaces, see “Introduction to the SCL Tutorial”
on page 151 and “INTERFACE” on page 475.
Example
The following INTERFACE block declares two methods for reading and writing data.
interface Reader;
Read: method return=string;
Write: method data:string;
endinterface;
Only the method declarations are given in the INTERFACE block. The method
implementations are given in any class that supports the interface.
For example, the Lst and Ddata classes both implement the Read and Write methods.
These classes support the Reader interface. In the Lst class, these methods read and write
items from and to an SCL list.
class Lst supports Reader;
dcl list listid;
dcl num cur n rc;
/* Override the class constructor. */
/* Create a new list.
*/
Lst: method/(state='o');
listid = makelist();
cur = 0;
n = 0;
endmethod;
Read: method return=string;
if (cur >= n) then do;
put 'End of file';
return "";
end;
else do;
cur + 1;
/* Get the current item from the list. */
dcl char item;
item=getitemc(listid,cur);
return item;
144
Chapter 8
•
SAS Object-Oriented Programming Concepts
end;
endmethod;
Write: method c:string;
n + 1;
/* Insert a new item into the list. */
rc=insertc(listid,c,-1);
endmethod;
endclass;
The method implementations in the Ddata class read and write data from and to a SAS
table.
class Ddata supports Reader;
protected num fid;
protected num obs n;
dcl num rc;
/* Override the class constructor. */
/* Use the open function to open a SAS table. */
Ddata: method name: string mode: string;
fid = open(name, mode);
obs = 0;
n = 0;
endmethod;
Read: method return=string;
if (obs >= n) then do;
put 'End of file';
return "";
end;
else do;
dcl string c;
/* Fetch an observation from the table. */
obs + 1;
rc=fetchobs(fid, obs);
/* Get the contents of table column 1. */
c = getvarc(fid, 1);
return c;
end;
endmethod;
Write: method c:string;
dcl num rc;
/* Add a new row to the table and
*/
/* write the contents of C into column 1. */
rc=append(fid);
call putvarc(fid, 1, c);
rc = update(fid);
n + 1;
endmethod;
Converting Version 6 Non-Visual Classes to SCOM Classes
145
endclass;
Using the interface, you can read and write data without knowing the data source. In the
following example, the Read class implements method M, which calls the method that
was declared in the Reader interface. The interface determines which method
implementation is executed.
class Read;
M: method r:Reader;
/* Write a string to the data source, */
/* then read it back.
*/
r.write("abc");
put r.read();
endmethod;
endclass;
The following labeled program section reads and writes data to both a list and a SAS
table. This code passes a Lst class and a Ddata class to the Read class, which treats the
list and the table in the same way. The data is read and written transparently. The Read
class does not need to know what the actual implementation of the Reader is — it only
needs to know the interface.
init:
dcl Lst L = _new_ Lst();
dcl Ddata D = _new_Ddata("test","un");
dcl read R = _new_ read();
R.M(L);
R.M(D);
return;
Converting Version 6 Non-Visual Classes to
SCOM Classes
Introduction
You do not need to convert Version 6 classes to SAS Component Object Model (SCOM)
classes in order to run programs from the previous versions. Version 6 classes are
automatically loaded into SCOM formats when they are instantiated. Existing Version 6
SCL programs should run normally in Version 8 and beyond.
However, you can use the (SCOM) features that first appeared in Version 8 to make
your programs more object-oriented, easier to maintain, and more efficient. Using
SCOM features also enables you to reuse model classes in the future development of
client/server applications.
To convert Version 6 model classes to SCOM classes, you must modify the method
implementation files and regenerate the class files. To modify the method
implementation files, follow these steps:
1. Remove global variables. Declare them as private attributes or, if they are referenced
in only one method, declare them as local variables within that method. See
“Removing Global Variables” on page 146 for more information.
2. Declare all variables. See “Declaring Variables” on page 146 for more information.
146
Chapter 8
•
SAS Object-Oriented Programming Concepts
3. Convert labels to method names and convert LINK statements to method calls.
Declare the labeled sections as private methods. If necessary, specify the
Forward='Y' option for the method. See “Converting Labels and LINK
Statements” on page 147 for more information.
4. Convert CALL SEND statements to dot notation. See “Converting CALL SEND to
Dot Notation” on page 148 for more information.
To regenerate the class files, follow these steps:
1. Use CREATESCL to convert Version 6 class files to SCOM class files. See
“Converting Class Definitions with CREATESCL” on page 148 for more
information.
2. Convert instance variables to attributes, if appropriate. See “Using Instance
Variables” on page 149 for more information.
3. Make sure signatures are generated for all methods. The best way to ensure that
signatures are generated is to delete the method declarations from the class files and
to replace them with the METHOD blocks from the method implementation files.
4. Change the class names specified in the CLASS statements if you do not want to
overwrite the existing Version 6 classes.
5. Issue the SAVECLASS command to generate the new SCOM class.
Removing Global Variables
Remove all global variables from the Version 6 method implementation entries. Convert
them either to local variables through DECLARE or to private attributes in the class
definition file. For example, suppose that a Version 6 method implementation file
contains the variables N1, N2, C1 and C2 as shown:
length n1 n2 8;
length c1 c2 $200;
In this example, four attributes need to be added to mylib.classes.newclass.scl,
as follows:
Private
Private
Private
Private
num n1;
num n2;
char c1;
char c2;
After the attributes are added, issue the SAVECLASS command to generate the new
class.
Declaring Variables
Declare all of the variables in your program. Lists should be declared with the LIST
keyword rather than allowing them to default to a Numeric type. Objects should be
declared either as generic objects (with the OBJECT keyword) or as specific class
objects. You can use dot notation with an object only if it is declared as an object. Using
specific LIST and object declarations can avoid problems with overloading methods. For
more information, see “Overloading and List, Object, and Numeric Types” on page 123.
Whenever possible, classes should be declared with a specific class declaration such as
dcl work.a.listbox.class lboxobj;
Converting Version 6 Non-Visual Classes to SCOM Classes
147
Try to avoid using generic object declarations such as
dcl object lboxobj;
Also, the compiler cannot check method signatures or validate methods and attributes if
it does not know the specific class type. If the compiler is not able to do this checking
and validation at compile time, then SCL must do it at run time, which makes your
program less efficient.
For example, assume that you declare a generic object named SomeC that has a method
Get, which returns a numeric value. You also declare a class named XObj that has a
method M, which is overloaded as (N)V and (C)V. Suppose you need to pass the return
value of Get to the M method:
dcl object SomeC = _new_ someclass.class();
dcl work.a.xclass.class XObj = _new_ xclass.class();
XObj.M(SomeC.Get());
SomeC is declared as a generic object, so the compiler cannot determine what object it
contains at compile time. Even though there is a specific object assignment to SomeC,
the compiler cannot guarantee what type it will contain at any given point, because the
value could be changed elsewhere when the program runs.
Therefore, the compiler cannot look up the Get method to find that it returns a Numeric
value, and it cannot determine which method M in Xclass to call. This method validation
must be deferred until run time, when the return type of the Get method will be known
(because the actual call will have taken place and the value will have been returned).
The problem can be remedied by declaring SomeC as a specific object:
dcl someclass SomeC = _new_ someclass.class();
If this is not possible, then you could declare a Numeric variable to hold the result of the
Get method, as shown in this example:
dcl object SomeC = _new_ someclass.class();
dcl xclass XObj = _new_ xclass.class();
dcl num n;
n = SomeC.Get();
XObj.M(n);
Even though the compiler cannot validate the Get method for the SomeC class, it can
validate the method name and parameter type for XObj.
Converting Labels and LINK Statements
The next step is to remove all link labels from the Version 6 method implementation
catalog entries. Convert them to private methods in the class definition file, and convert
the link to a method call. For example, suppose that myclass.classes.old.scl
contains the following:
m1: method;
link a1;
endmethod;
a1:
...SCL statements...
return;
To change the labeled section to a private method in
mylib.classes.newclass.scl, add the following:
148
Chapter 8
•
SAS Object-Oriented Programming Concepts
a1: Private method;
...SCL statements...
endmethod;
If needed, you can also add parameters to the method. To change the link to a method
call, change the following:
m1: method;
a1();
endmethod;
In the old entry, the A1 labeled section is after the M1 method. In the new entry, the
labeled section has been converted to a method. However, you cannot call a method
before it is declared. To fix this problem, you must either move the A1 method before
the M1 method, or you can declare A1 with the Forward='Y' option:
a1: Private method / (Forward='y');
...SCL statements...
endmethod;
Converting CALL SEND to Dot Notation
The final step in modifying your method implementation files is converting CALL
SEND statements to METHOD calls that use dot notation.
Note: To use dot notation, the method that you specify must have a signature.
Therefore, you cannot convert CALL SEND statements to dot notation unless your
class files have been converted to SCOM class files. Also, the object that you specify
should be declared as a specific class type to enable the compiler to validate method
parameters.
For example, suppose that a Version 6 program contains the following line:
call send(obj1,'m1',p1);
Converting this line to dot notation results in
obj1.m1(p1);
Converting Class Definitions with CREATESCL
Assume that the Version 6 class is mylib.classes.oldclass.class and that the
method implementation file is mylib.classes.old.scl.
1. Use CREATESCL to create an SCL entry that contains the following SCL
statements:
Init:
rc=createscl('mylib.classes.oldclass.class',
'mylib.classes.newclass.scl');
return;
2. Issue the SAVECLASS command to generate the Version 6 class file
mylib.classes.newclass.class.
3. Open this entry in the Build window and modify the class definition as needed.
Reissue the SAVECLASS command to generate the new class file in SCOM format.
Converting Version 6 Non-Visual Classes to SCOM Classes
149
Using Instance Variables
The object model in Version 6 uses instance variables. In Version 8, instance variables
were replaced with attributes.
When a class is loaded, the class loader automatically converts Version 6 formats to the
SCOM format. This process includes converting instance variables to public or private
attributes with the option IV, which specifies the name of the Version 6 instance
variable.
In the following example, the Version 6 instance variable ABC is converted to the
SCOM attribute abc.
class IVclass;
public char abc / (iv='ABC');
endclass;
150
Chapter 8
•
SAS Object-Oriented Programming Concepts
151
Chapter 9
Example: Creating An ObjectOriented Application in SCL
Introduction to the SCL Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Simple Class Syntax in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Creating a Data Set Class in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Class Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
The Data Set Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Using the Data Set Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Extending Classes in SCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Access Modifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
The DDATA Class as a Subclass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
The FDATA Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
Overloaded Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Interfaces and Higher Levels of Abstraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Other Classes and Further Abstraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
The SCL USECLASS Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Using SCL Class Syntax with SAS/AF Software . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Flexibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Introduction to the SCL Tutorial
SCL provides many object-oriented programming features such as class and useclass
syntax, method overloading, and interfaces. This tutorial demonstrates how to use many
of these features by creating a class-based version of a simple data input facility that is
based on traditional SCL library functions.
Simple Class Syntax in SCL
Before beginning the tutorial, you must have a clear understanding of a simple SCL
class. A CLASS statement enables you to use SCL to create a SAS/AF class and to
152
Chapter 9
•
Example: Creating An Object-Oriented Application in SCL
define all the properties for the class, including attributes, methods, events, and
interfaces. An SCL class is created with SCL class syntax. The simplest class is an
empty class, which is defined using the following code:
class x;
endclass;
Enter the above code in an SCL entry such as X.SCL and then create the class by using
the SAVECLASS command. You should now see a CLASS entry for X in the current
catalog.
Note: The name of the entry does not have to match the name of the class, but for
beginners this is the easiest way to name an entry.
To add functionality to this class, you can create a simple method by using the following
code:
class x;
m: method;
put 'Hello';
endmethod;
endclass;
The PUT statement will write Hello to the SAS procedure output file or to a file that is
specified in the most recent FILE statement. To run this method, you need to create an
example of the class and call the method. In an SCL entry called Y.SCL, enter the
following code:
init:
dcl x x = _new_ x();
x.m();
return;
The _NEW_ operator is used to create an example of the class X and to assign it to the
variable x. The _NEW_ operator provides a faster and more direct way to create an
object by combining the actions of loading a class with LOADCLASS and initializing
the object with the _new method, which invokes the object's _init method. You then call
method M using the object variable x in the dot notation expression x.m().
Note: Dot notation provides a shortcut for invoking methods and for setting or querying
attribute values. Using dot notation reduces typing and makes SCL programs easier
to read. It also enhances run-time performance if you declare the object used in the
dot notation as an example of a predefined class instead of a generic object. The
object's class definition is then known at compile time. Because dot notation checks
the method signature, it is the only way to access an overloaded method as illustrated
in “Overloaded Methods” on page 159.
Compile Y.SCL, and then use the TESTAF command to run it. You should see the
following output:
Hello
Creating a Data Set Class in SCL
153
Creating a Data Set Class in SCL
Introduction
In this exercise you will read a simple SAS data set that contains two character variables.
You will learn how to open the data set, fetch an observation, copy a data set character
variable, and close the data set. The SCL functions that will be used are
•
OPEN
•
FETCH
•
GETVARC
•
CLOSE
You will build a class that encapsulates these operations so that they can be called as
methods on any given data set. Because of this, the class itself should represent a data
set.
Before you can begin converting these functions to class methods, you must create the
class data, as shown in the next section, “Class Data” on page 153.
Class Data
Class data is declared with the DCL statement by using the following code:
class x;
dcl num n;
endclass;
Here class X contains a numeric variable called n.
The DCL statement can be omitted when you provide a variable scope modifier such as
public, private or protected. Scope modifiers indicate how the variable is to be accessed
from locations outside the class. By default, the scope modifier is public, which indicates
that anyone can access the variable. Both private and protected scope modifiers restrict
access to the variable.
The Data Set Class
For the data set class, begin with the following class data:
class DDATA;
public string
public string
protected num
protected num
endclass;
dname;
mode;
fid;
nvars;
where
dname
is the name of the data set
mode
is the access mode
154
Chapter 9
•
Example: Creating An Object-Oriented Application in SCL
fid
is the file identifier that will be returned from the OPEN call
nvars
is the number of variables in the data set.
In this case, public access is given to dname and mode, but access is restricted for fid and
nvars.
You will create one method for each of the SCL functions OPEN, FETCH, GETVARC,
and CLOSE. The following example shows how to use the FETCH function to take an
action that is based on the value of its return code:
read: method return=num;
dcl num rc;
rc = fetch(fid);
return rc;
endmethod;
You can use a function such as GETVARC directly in the IF statement. In this case, the
VARTYPE function is executed, and then the IF expression evaluates the return code to
determine whether to perform the conditional action. The following method takes a
parameter n, which represents the variable number, and returns the character variable c
from GETVARC.
cpy: method n: num return=string;
dcl string c = "";
if (vartype(fid, n) = 'C') then
c = getvarc(fid, n);
return c;
endmethod;
CLOSE is used to close a data set as soon as it is no longer needed by the application.
The method in this example for CLOSE is
_term: method /(state='O');
if (fid) then close(fid);
_super();
endmethod;
This method closes the data set represented by fid. It also contains two items that refer to
the parent class of DDATA (State='O' and _super()). A parent class is the class from
which a particular class was extended or derived. In this case, DDATA was implicitly
extended from OBJECT.CLASS. Since OBJECT.CLASS contains a _term method, you
must indicate that you are overriding it in DDATA by specifying State='O'. Because
OBJECT.CLASS is being overridden, to ensure that the _term method in
OBJECT.CLASS is still executed, use the function call _super().
Constructors
The method that will be used for opening the data set is called a constructor. A
constructor is a method that is used to instantiate a class and provides a way for
initializing class data. In order for a method to be a constructor, it must be a void method
(one that does not have a return value), and it must have the same name as the class.
Here is the constructor for DDATA:
ddata: method n: string m:string nv:num;
fid = open(n, m);
dname = n;
mode = m;
Creating a Data Set Class in SCL
155
nvars = nv;
endmethod;
where n is a parameter containing the name of the data set, m is the input mode, and nv is
the number of variables.
This constructor method will be called when an example of the DDATA class is created
using the _NEW_ operator. For example, the following code creates an example of the
DDATA class representing the data set sasuser.x. The data set will be opened in
input mode and has two variables.
init:
dcl ddata d = _new_ ddata("sasuser.x", "i", 2);
return;
Using the Data Set Class
The entire data set class is
class ddata;
/* Data */
public string
public string
protected num
protected num
dname;
mode;
fid;
nvars;
/* Constructor method */
ddata: method n: string m:string nv:num;
fid = open(n, m);
dname = n;
mode = m;
nvars = nv;
endmethod;
/* FETCH method */
read: method return=num;
dcl num rc;
rc = fetch(fid);
return rc;
endmethod;
/* GETVARC method */
cpy: method n: num return=string;
dcl string c = "";
if (vartype(fid, n) = 'C') then
c = getvarc(fid, n);
return c;
endmethod;
/* CLOSE method */
_term: method /(state='O');
if (fid) then close(fid);
_super();
endmethod;
endclass;
156
Chapter 9
•
Example: Creating An Object-Oriented Application in SCL
You can use this class as follows:
init:
dcl ddata d = _new_ ddata("sasuser.x", "i", 2);
dcl num more = ^d.read();
do while(more);
dcl string s s2;
s = d.cpy(1);
s2 = d.cpy(2);
put s s2;
more = ^d.read();
end;
d._term();
return;
In this example, the data set sasuser.x has two character variables, which you read
and print until the end of the file is reached.
Now suppose that you create the following data set:
data sasuser.x;
input city $1-14;
length airport $10;
if city='San Francisco' then airport='SFO';
else if city='Honolulu' then airport='HNL';
else if city='New York' then airport='JFK';
else if city='Miami' then airport='MIA';
cards;
San Francisco
Honolulu
New York
Miami
;
The output from the program will be
San Francisco SFO
Honolulu HNL
New York JFK
Miami MIA
Extending Classes in SCL
Introduction
While designing the class structure, you might find that some classes share functionality
with other classes. In that case, you can extend classes by creating subclasses to prevent
duplication of functionality.
In “Constructors” on page 154 , the DDATA class implicitly extended OBJECT.CLASS.
In fact, any class without an explicit EXTENDS clause in the CLASS statement extends
OBJECT.CLASS. To explicitly extend a class, add the EXTENDS clause shown below:
class y extends x;
endclass;
Extending Classes in SCL
157
In this case, class Y extends the class X. Alternatively, Y is a subclass of X, and X is the
parent class of Y.
This enables Y to share X's functionality. For example, if the class X were
class x;
m: method;
put 'Hello';
endmethod;
endclass;
and the class y were
class y extends x;
endclass;
then you could call the method M using an example of the class Y:
init:
dcl y y = _new_ y();
y.m();
return;
Access Modifiers
The access modifiers that we mentioned above – public, private and protected – can now
be explained. A variable (or method) that is declared as public can be accessed
anywhere. A variable (or method) that is declared as protected can be accessed only by
non-proper subclasses of the class in which its declared. Protected variables can be
accessed only from the class in which they are declared. This is also true for protected
variables that are accessed from the subclasses of those classes.
These modifiers restrict access to certain variables (or methods) that should not be seen
outside the class or class hierarchy in which they are declared. For example, there is no
need for any class outside the DATA class hierarchy to access the fid variable, so it is
declared as protected but could also be declared as private.
The DDATA Class as a Subclass
To illustrate how subclassing works with the DDATA class, this exercise creates a
similar class for external data files. The following SCL functions will be used:
•
FOPEN
•
FREAD
•
FGET
•
FCLOSE
These SCL functions will be used to create a class called FDATA to represent an
external file. It is important to note similarities to the DDATA class. In particular, each
class will have a name, input mode, and file identifier, so a class will be created to store
this information. Then the subclasses DDATA and FDATA will be created from the
DATA class. The parent data class will be
class data;
public num type;
public string dname;
public string mode;
protected num fid;
158
Chapter 9
•
Example: Creating An Object-Oriented Application in SCL
data: method f: num n: string m:string;
fid = f;
dname = n;
mode = m;
endmethod;
endclass;
In addition to the name, mode and file id, a type variable is stored to indicate whether
FDATA is an external file or a SAS data set.
The constructor DATA will be called whenever an example of the DATA class is
created. It will also be called automatically whenever any subclasses of data are created
if the constructor in the subclass has not be overridden. If the constructor has been
overridden, you must use _super to call the parent constructor. You must also use _super
if the argument list that is used in the _NEW_ operator does not match the argument list
of the parent constructor. This will be the case for DDATA and FDATA.
To extend the DATA class, modify the DDATA CLASS statement, data declarations,
and constructor as follows:
class ddata extends data;
/* Class data */
protected num nvars;
/* Constructor method */
ddata: method n: string m:string nv:num;
fid = open(n, m);
_super(fid, n, m);
nvars = nv;
type = 1;
endmethod;
In this example, the DDATA constructor will call the data constructor via the _super
call. This sets the name, mode and file identifier that are stored in the parent class data.
The DDATA constructor still sets nvars and also sets the type field to indicate that the
file is a data set. The rest of the class will remain the same.
The FDATA Class
The declaration and constructor of the FDATA class will be similar to those of the
DDATA class, as shown in the following:
class fdata extends data;
/* Constructor method */
fdata: method n: string m: string;
dcl string ref = "";
dcl num rc = filename(ref, n);
fid = fopen(ref, m);
_super(fid, n, m);
type = 2;
endmethod;
/* FREAD method */
read: method return=num;
Extending Classes in SCL
159
dcl num rc = fread(fid);
return rc;
endmethod;
/* FGET method */
cpy: method n: num return=string;
dcl string c = "";
dcl num rc = fget(fid, c);
return c;
endmethod;
/* FCLOSE method */
_term: method /(state='O');
if (fid) then fclose(fid);
_super();
endmethod;
endclass;
Use FDATA to read an external class by instantiating it and looping through the data:
init:
dcl fdata f = _new_ fdata("some_file", "i");
dcl num more = ^f.read();
do while(more);
dcl string s s2;
s = f.cpy(1);
s2 = f.cpy(2);
put s s2;
more = ^f.read();
end;
f._term();
return;
This code assumes that the external file is formatted with each line containing two
character variables separated by a blank. For example:
Geoffrey Chaucer
Samuel Johnson
Henry Thoreau
George Eliot
Leo Tolstoy
Overloaded Methods
Method overloading is the process of defining multiple methods that have the same
name, but which differ in parameter number, type, or both. Method overloading lets you
use the same name for methods that are related conceptually but take different types or
numbers of parameters.
For example, you may have noticed that the CPY method in FDATA has a numeric
parameter that apparently serves no useful purpose. You do not need to specify a
variable number for an external file. This parameter is used so that in the future when
you use interfaces, the CPY method in FDATA matches the one in DDATA. For now,
the parameter is not needed. One way of resolving this is to overload the CPY method by
creating another CPY method with a different parameter list, as shown in the following
code:
cpy: method return=string;
160
Chapter 9
•
Example: Creating An Object-Oriented Application in SCL
dcl string c="";
dcl num rc = fget(fid, c);
return c;
endmethod;
cpy: method n: num return=string;
return cpy();
endmethod;
In this example, the original CPY method ignores the parameter and calls a CPY method
that returns the character value. By doing this, you have defined two methods that have
the same name but different parameter types. With this simple change, you do not have
to worry about which method to call.
The CPY method can be used as follows:
s = f.cpy();
Overloaded methods can be used any time you need to have multiple methods with the
same name but different parameter lists. For example, you may have several methods
that are conceptually related but which operate on different types of data, or you may
want to create a method with an optional parameter, as in the CPY example.
To differentiate between overloaded methods, the compiler refers to the method
signature, which is a list of the method's parameter types. A method signature provides a
means of extending a method name, so that the same name can be combined with
multiple different signatures to produce multiple different actions. Method signatures are
created automatically when a method is added to a class and when the compiler is
parsing a method call. Method signatures appear as part of the information that the Class
Editor displays about a method.
Interfaces and Higher Levels of Abstraction
The routines that use DDATA and FDATA are very similar. In fact, the set of methods
for each class is similar by design. The actual implementations of the methods differ. For
example, the CPY method in DDATA is different from the CPY method in FDATA, but
the basic concept of reading character data is the same. In effect, the interface for both
classes is essentially the same.
You can exploit this similarity to make it easier to use the two classes. In fact, you can
have one data loop that handles both types of classes by defining an SCL interface for
both classes. To define the interface, you generalize the functionality and create the
following SCL entry:
interface reader;
read: method return=num;
cpy: method n: num return=string;
endinterface;
Use SAVECLASS to create an interface entry with two abstract methods, READ and
CPY. The abstract methods are by definition the interface itself. Any class that supports
this interface will need to supply the implementations for these methods.
When you use the SAVECLASS command in an SCL entry that contains a CLASS
block, the class is generated and its CLASS entry is created. This is the equivalent of
using the Class Editor to interactively create a CLASS entry.
Interfaces and Higher Levels of Abstraction
161
Once you have created the interface, you must modify the DDATA and FDATA classes
to support it. To do that, change the CLASS statements in each class as follows:
class ddata extends data supports reader;
and
class fdata extends data supports reader;
Since DDATA and FDATA contain READ and CPY methods, no other changes are
needed in the classes.
To use the new interface, you will create two helper classes. One is an iterator class that
will be used to abstract the looping process over both DDATA and FDATA. Use the
following code to create the two helper classes:
class iter;
private num varn nvars;
public reader r /(autocreate='n');
/* Constructor */
iter: method rdr: reader n: num;
varn = 1;
nvars = n;
r = rdr;
endmethod;
/* Check if there are more elements to iterate over */
more: method return=num;
dcl num more = ^r.read();
varn = 1;
return more;
endmethod;
/* Return the next element */
next: method return=string;
dcl string c = "";
c = r.cpy(varn);
varn + 1;
return c;
endmethod;
endclass;
Several things require explanation for this class. First, note that it has two private
variables, varn and nvars, to keep track of where it is in the iteration process.
It also has a variable r which is an interface type. Since we cannot create the interface
automatically when an example of ITER is created, we specify the AUTOCREATE='N'
option.
The iterator has three methods. In the first method, the constructor stores the reader
variable and the number of variables in the reader. A reader variable is any class that
supports the READER interface. The MORE method reads from the reader to check
whether there are any more elements. The NEXT method returns the next element.
The other helper class uses the iterator to loop over the data in a reader.
class read;
162
Chapter 9
•
Example: Creating An Object-Oriented Application in SCL
private iter i;
read: method r: reader;
i = _new_ iter(r, 2);
endmethod;
loop:method;
do while(i.more());
dcl string s s2;
s = i.next();
s2 = i.next();
put s s2;
end;
endmethod;
_term: method /(state='O');
i._term();
_super();
endmethod;
endclass;
The constructor will create a new iterator, and the LOOP method will use it to loop over
the data.
The SCL to use these classes is
init:
dcl string filename;
dcl fdata f;
dcl ddata d;
dcl read r;
/* Read an external file */
filename = "some_file";
f = _new_ fdata(filename, "i");
r = _new_ read(f);
r.loop();
r._term();
/* Read a data set */
filename = "sasuser.x";
d = _new_ ddata(filename, "i", 2);
r = _new_ read(d);
r.loop();
r._term();
return;
This code will successively read an external file and a data set.
Other Classes and Further Abstraction
Given the reader interface, you can now use other classes – even ones outside the data
class hierarchy – as readers, as long as they support the reader interface. Using the
Other Classes and Further Abstraction
abstract reader interface enables you to read from many different types of objects as
well.
For example, consider the following class, which uses SCL lists to maintain data:
class lst
private
private
private
private
supports reader;
list listid;
num nvars;
num nelmts;
num cur;
/* Constructor */
lst: method n:num;
listid = makelist();
nvars = n;
nelmts = 0;
cur = 1;
endmethod;
/* Copy method */
cpy: method n: num return=string;
dcl string c = "";
if (cur <= nelmts) then do;
c = getitemc(listid, cur);
cur + 1;
end;
return c;
endmethod;
/* Read method */
read: method return=num;
if (cur > nelmts) then
return 1;
else
return 0;
endmethod;
/* Add an element to the list */
add: method c:string;
nelmts + 1;
rc = setitemc(listid, c, nelmts, 'Y');
endmethod;
/* Add two elements to the list */
add: method c1:string c2:string;
add(c1);
add(c2);
endmethod;
/* Terminate the list */
_term: method /(state='O');
if listid then listid = dellist(listid);
_super();
endmethod;
endclass;
163
164
Chapter 9
•
Example: Creating An Object-Oriented Application in SCL
This class represents a list, and because it supports the READER interface, it can be read
in the same way as the DDATA and FDATA classes.
The SCL for reading from the list is
init:
dcl lst lstClassID;
dcl read r;
lstClassID = _new_ lst(2);
/* Notice the overloaded add method */
lstClassID.add("123", "456");
lstClassID.add("789", "012");
lstClassID.add("345", "678");
/* Create a read class and loop over the data */
r = _new_ read(lstClassID);
r.loop();
r._term();
return;
The output for this program will be
123 456
789 012
345 678
The SCL USECLASS Statement
This section presents the USECLASS statement and is intended for those users who are
unfamiliar with USECLASS. It is not required for the remainder of the tutorial.
A USECLASS statement binds methods that are implemented within it to the specified
class definition. USECLASS allows a class's method implementations to reside in
different entries other than the class declaration's entry. This is helpful if a class is
complex enough to require several developers to write its methods.
The DDATA class will be modified to use USECLASS. Although this class is certainly
not complex enough to require USECLASS, it illustrates its use.
First, rewrite the class specification, using the following code:
class ddata;
/* Data */
public string
public string
protected num
protected num
dname;
mode;
fid;
nvars;
/* Constructor method */
ddata: method n: string m:string nv:num /
(scl='sasuser.a.constr.scl');
/* FETCH method */
read: method return=num
/
The SCL USECLASS Statement
165
(scl='sasuser.a.read.scl');
/* GETVARC method */
cpy: method n: num return=string
(scl='sasuser.a.cpy.scl');
/* CLOSE method */
_term: method
(state='O', scl='sasuser.a.trm.scl');
endclass;
/
/
The method implementations are removed, and the method declaration statements are
modified to indicate which SCL entry contains each method implementation. This new
class specification should be compiled with the SAVECLASS command.
Next, create the method implementations in each entry. These should be compiled with
the COMPILE command, not with SAVECLASS. SASUSER.A.CONSTR.SCL should
contain
useclass ddata;
/* Constructor method */
ddata: method n: string m:string nv:num;
fid = open(n, m);
dname = n;
mode = m;
nvars = nv;
endmethod;
enduseclass;
SASUSER.A.READ.SCL should contain
useclass ddata;
/* FETCH method */
read: method return=num;
dcl num rc;
rc = fetch(fid);
return rc;
endmethod;
enduseclass;
SASUSER.A.CPY.SCL should contain
useclass ddata;
/* GETVARC method */
cpy: method n: num return=string;
dcl string c = "";
if (vartype(fid, n) = 'C') then
c = getvarc(fid, n);
return c;
endmethod;
enduseclass;
SASUSER.A.TRM.SCL should contain
166
Chapter 9
•
Example: Creating An Object-Oriented Application in SCL
useclass ddata;
/* CLOSE method */
_term: method /(state='O');
if (fid) then close(fid);
_super();
endmethod;
enduseclass;
Using SCL Class Syntax with SAS/AF Software
Introduction
So far you have created stand-alone SCL classes. SCL class syntax can be used to create
SAS/AF visual objects.
This exercise will extend the SAS/AF List Box class. The readers that were previously
developed in this tutorial will be used to read data that will be used to initialize the items
in the List Box.
To extend the List Box class, you must write a class to extend List Box and modify the
READ class that was created in “Other Classes and Further Abstraction” on page 162.
The READ class will then be able to pass the new class to the list box to use for
initializing the item list instead of having it simply print the character data after reading
it.
You must create a new interface and make a minor modification to the LOOP method in
READ.
The interface has a single method, CALLBACK:
interface call;
callback: method s:string;
endinterface;
The modified LOOP method in READ is
loop: method caller:call;
do while(i.more());
caller.callback(i.next());
end;
endmethod;
The method now takes a CALL interface parameter and calls its CALLBACK method.
Note: You do not specify the implementation of a method in an interface; you simply
supply the name and parameter list.
It is not necessary to know what the implementation for CALLBACK is at this point,
only that you call it in the read loop and pass a character value to it. Whatever class
supports the interface will supply the implementation for CALLBACK.
Now, create the extended List Box class (depending on which version of SAS you have,
you may need to create an empty MLIST class first in order for the following to work).
import sashelp.classes;
class mlist extends listbox_c supports call;
Using SCL Class Syntax with SAS/AF Software
167
/* Local item list */
private list listid;
/* Set method */
set: method r: read;
listid = makelist();
r.loop(_self_);
endmethod;
/* Store the character value in the local list */
callback: method s:string;
rc = insertc(listid, s, -1);
endmethod;
/* Set the items attribute */
setattr: method;
_self_.items = listid;
endmethod;
endclass;
Note how the IMPORT statement and the LOOP, SET, SETATTR, and CALLBACK
methods will be used:
•
The IMPORT statement defines a search path for CLASS entry references in an SCL
program so that you can refer to a class by its two-level name instead of having to
specify the four-level name each time. It is used to specify a catalog to search for
abbreviated class names. For example, the MLIST class extends LISTBOX_C, but if
LISTBOX_C is not in the current catalog, the compiler will not know where to find
it. The IMPORT statement tells the compiler to search the SASHELP.CLASSES
catalog for any classes it cannot find in the current catalog.
•
The SET method is used to set up a local list that will hold the new set of items for
the list box. It will also call the LOOP method in READ, with MLIST's object as a
parameter. Recall that MLIST supports the CALL interface, so this will work with
the new LOOP method that was created above.
•
As the LOOP method executes, it will call the CALLBACK method for each
character variable that it reads. The CALLBACK method will store the variable in
the local list that was created in the SET method.
•
Finally, the SETATTR method will assign the local list to MLIST's item list, thus
changing the list of items seen when the List Box, which is actually MLIST, is
displayed.
To see how this works, create the CALL interface, as well as the classes READ and
MLIST, by using the SAVECLASS command. Then edit a frame. In the Components
window, add the MLIST class to the class list (via AddClasses on the pop-up menu).
After it appears on the list, drag and drop MLIST to the frame. In the frame's source,
enter
init:
dcl ddata d;
dcl read r;
dcl string filename = "sasuser.x";
d = _new_ ddata(filename, "i", 2);
r = _new_ read(d);
mlist1.set(r);
mlist1.setattr();
168
Chapter 9
•
Example: Creating An Object-Oriented Application in SCL
return;
This will create a DDATA reader with an associated READ class. Now call the SET and
SETATTR methods on the new List Box class (MLIST).
Compile and use the TESTAF command on the frame. The initial list of items will be
San Francisco
Honolulu
New York
Miami
Flexibility
Using the CALL interface in the above exercise allows a great deal of flexibility in
modifying the MLIST and READ classes.
For example, to process numeric data instead of character data, you could simply
overload the CALLBACK method in the interface
interface call;
callback: method s:string;
callback: method n:num;
endinterface;
and support it in the MLIST class
callback: method n:num;
/* process numeric value */
endmethod;
Now, the READ class – or any class that supports CALL – can call the CALLBACK
method with a numeric parameter. Clearly, this process can be generalized to make use
of any possible parameter lists that are needed for CALLBACK.
Another feature is that any class that supports the READER interface can be used to read
the data into the list box. For example, to use an external file, change the frame's SCL to
init:
dcl fdata f;
dcl read r;
dcl string filename = "some_file";
f = _new_ fdata(filename, "i");
r = _new_ read(f);
mlist1.set(r);
mlist1.setattr();
return;
We can consolidate the code further by creating another class to set up the reader:
init:
dcl SetReader g = _new_ SetReader();
dcl read r = g.get();
mlist1.set(r);
mlist1.setattr();
return;
SetReader sets up whatever reader is necessary even if your program is using external
data. Then, at the frame level, you can read from any type of data source, such as a data
set, an external file, an SCL list, or any other user-defined data source. The only
requirement is that SetReader support the reader interface.
169
Part 3
Application Considerations
Chapter 10
Handling Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Chapter 11
Using SAS Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
Chapter 12
Using External Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
170
171
Chapter 10
Handling Exceptions
Introduction to SCL Exception Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Using the SCL programHalt Handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Handling SCL Exceptions with CATCH and THROW . . . . . . . . . . . . . . . . . . . . . 173
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
How SCL Determines Which CATCH Block To Execute . . . . . . . . . . . . . . . . . . . 175
Catching and Rethrowing Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
Nested CATCH Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
The SCL Throwable and SCL Exception Classes . . . . . . . . . . . . . . . . . . . . . . . . . 178
Introduction to SCL Exception Handling
SCL provides two mechanisms for handling error conditions:
The program halt handler
Program halt handlers typically allow your application to print a message, save some
information, and then either try to continue execution or halt the application. The
SCL generic program halt handler is sort of an all-purpose routine for handling
program halts that occur for a variety of different reasons at any point in the
program.
The CATCH and THROW statements
The SCL Exception class and the CATCH and THROW statements enable you to
define specific exceptions and recovery routines that are specific to each exception.
You can define the exceptions and recovery routines in the locations in your code
where the exceptions may be encountered, thus making error recovery code a natural
part of the program.
Using the SCL programHalt Handler
The programHalt handler is designed to handle unexpected run-time errors. The Program
Halt class contains methods that are called when certain run-time exceptions occur. By
overriding these methods, you can specify whether an application should halt
immediately or continue executing. You can control how exceptions are handled.
172
Chapter 10
•
Handling Exceptions
In the following example, the _onGeneric method creates a list named MSGS, inserts
information about the location where the application failed into the list, and displays the
list with the MESSAGEBOX function. You can use this code to create your own
program halt handler.
class myHalt extends
sashelp.classes.programHalt.class;
_onGeneric:method / (STATE='O');
dcl list msgs=makelist();
rc = insertc(msgs, "SCL program failed at ", 1);
rc = insertc(msgs, "Entry=" || entry, 2);
rc = insertc(msgs, "Line=" || putn(lineNumber, "3.0"), 3);
if (keywordType = 'function') then
rc = insertc(msgs, "Function=" || keyword, 4);
else
rc = insertc(msgs, "Method=" || keyword, 4);
rc = messageBox(msgs);
/* continue execution */
stopExecution = 'No';
endmethod;
endclass;
Note: Entry, lineNumber, keyword, and keywordType are all object attributes
that are defined in the class sashelp.classes.programHalt.class.
The _onGeneric method traps any error messages that are generated by SCL and saves
them in the MSGS list. Developers can use this list to identify and fix potential problems
in their code.
The programHalt handler must be declared at the beginning of your application. For
example:
dcl myHalt obj = _new_ myHalt();
Your program can instantiate multiple programHalt handlers, or your program may
instantiate only one handler, but then call a second program that instantiates its own
handler. The last programHalt handler that is instantiated is the current programHalt
handler. Only the current programHalt handler is active at any one time.
SCL uses a stack to keep track of programHalt handlers. Each time a programHalt
handler is instantiated, the new instance is pushed onto the stack. The handler on the top
of the stack is always the active handler. Before a program terminates it must terminate
(using the _term method) its programHalt handler. For example:
obj._term();
Terminating a programHalt handler pops it from the stack, and makes the next
programHalt handler on the stack the active handler.
For example, if your program instantiates the programHalt handler, and then calls
another SCL program, the second program may also instantiate a programHalt handler.
The second programHalt handler becomes the current programHalt handler. Before the
second program ends, it must terminate the second programHalt handler. The first
programHalt handler then becomes the current programHalt handler. If the second
programHalt handler is not terminated, it will remain active even after the program that
instantiated it has terminated.
Handling SCL Exceptions with CATCH and THROW
173
Handling SCL Exceptions with CATCH and
THROW
Introduction
All exceptions are subclasses of the SCL Exception class, which is a subclass of the SCL
Throwable class. You can use the CLASS statement to define your own exception
classes, and then use the THROW and CATCH statements to handle the exception.
Because an exception is a class, you can design the class to contain any information that
is relevant to recovering from the specific exception. A simple exception class may
contain only an error message. For example, the following class defines a subclass of
SCLException called NewException, which defines an error message string named
SecondaryMessage:
Example Code 10.1
NewException Class
Class NewException extends SCLException
dcl string SecondaryMessage;
endclass;
You can then create a new instance of NewException and raise this exception with the
THROW statement,as shown in the ThrowIt class:
Example Code 10.2
ThrowIt Class
Class ThrowIt;
m: method;
dcl NewException NE = _new_ NewException('Exception in method m');
NE.SecondaryMessage = "There's no code in m!";
throw NE;
endmethod;
endclass;
Note: You must always declare a variable to hold the thrown exception.
The code that processes the exception is enclosed in CATCH blocks. CATCH blocks
can contain any code needed to process the exception, including more CATCH and
THROW statements.
When an exception is thrown, normal execution of the entry stops, and SCL begins
looking for a CATCH block to process the thrown class. The CATCH block can contain
any statements needed to process the exception. For example, the following code prints
the stack traceback at the point of the throw.
do;
dcl NewException NE = _new_ NewException('Exception in method m');
NE.SecondaryMessage = "There's no code in m!";
throw NE;
catch NE;
put NE.getMessage();
call putlist(NE.traceback);
put NE.SecondaryMessage=;
/* Print exception information. */
/* Print secondary message. */
174
Chapter 10
•
Handling Exceptions
endcatch;
end;
Note: CATCH blocks must always be enclosed in DO statements.
The traceback information that is printed by this example is stored automatically by SCL
when an exception is thrown. See “The SCL Throwable and SCL Exception Classes” on
page 178 for more information.
Note: When a CATCH block has finished executing, control transfers to the end of the
current DO statement, and the program resumes normal execution. If no exception
has been thrown and SCL encounters a CATCH block, control transfers to the end of
the current DO statement and execution resumes at that location. Therefore, any SCL
statements the occur between CATCH blocks or following the last CATCH block
within the same DO group will never be executed. Any SCL statements within the
DO group that are not part of a CATCH block but must execute must be entered at
the beginning of the DO group.
After an exception is processed, program execution continues normally.
Example
Suppose you have the following class Y. This class defines a method called update that
throws an exception that is an instance of the SCL Exception class.
import sashelp.classes;
class Y;
update: method;
if (_self_.readOnly) then
/* Throw an exception. Set message via constructor. */
throw _new_ SCLException('Cannot update when in ready-only mode');
endmethod;
endclass;
Class X defines method M, which declares a local variable to hold the exception, and
then calls the update method, which throws the exception. The exception is then
processed by the CATCH block for SCLE.
import sashelp.classes;
class X;
M: method;
do;
/* Declare the local exception variable. */
dcl SCLException scle;
dcl Y y = _new_ y();
/* Call update method, which throws SCLEception. */
y.update();
/* Process the SCLException. */
catch scle;
/* Print exception information. */
put scle.getMessage();
call putlist(scle.traceback);
endcatch;
end;
endmethod;
endclass;
Handling SCL Exceptions with CATCH and THROW
175
How SCL Determines Which CATCH Block To Execute
SCL uses the scope of the DO group that contains the CATCH block and the class of the
exception to determine which CATCH block to execute.
•
SCL first looks in the scope of the DO group where the exception was initially
thrown. If SCL does not find a corresponding CATCH block, it expands its search
outward to the next enclosing DO group.
Note: If you are rethrowing an exception that has been thrown and caught at least
once already, then SCL automatically passes the exception outside of the DO
group where the exception was rethrown.
SCL continues expanding the scope of its search until it finds a corresponding
CATCH block or it has searched the current SCL entry. If the current SCL entry
does not contain a CATCH block for the thrown class, then the exception is passed
up the stack to the calling entry where the process is repeated. If the calling entry
contains a CATCH statement for the thrown class, then execution resumes at the
location of the CATCH statement. If the calling entry does not contain a CATCH
statement for the thrown class, then the exception is passed up the stack until SCL
finds a corresponding CATCH statement or until the stack is completely unwound. If
SCL does not find a corresponding CATCH statement, then the exception is treated
the same as a program halt.
•
SCL uses the class hierarchy to determine which CATCH block to execute. Within
the scope that it is currently searching, SCL chooses the CATCH block for the class
that is most closely related to the class of the thrown exception. For example, if the
current scope contains a CATCH block for the thrown class, then SCL will execute
that CATCH block. If the current scope does not contain a CATCH block for the
thrown class, but does contains a CATCH block for the parent class of the thrown
exception, then SCL will execute the CATCH block for the parent class. If none of
the CATCH blocks in the current scope are related to the thrown class, then SCL
continues its search for an appropriate CATCH block.
Suppose that in addition to the NewException class (see Example Code 10.1 on page
173 ) you define a subclass of NewException called SubException:
Example Code 10.3
NewException Class
Class NewException extends SCLException
dcl string SecondaryMessage;
endclass;
Example Code 10.4
SubException Class
Class SubException extends NewException
...code to process SubExceptions...
endclass;
As with all exceptions, SCL first searches the current DO group for a CATCH block that
is related to the thrown class. In this example, because NEsub is an instance of
SubException and SubException is a subclass of NewException, SCL will execute the
CATCH block for NE because it is in the scope of the current DO group. The CATCH
block for NEsub is in a different scope (the outer DO group), so it will not be executed
unless the CATCH block for NE is modified to rethrow (see “Catching and Rethrowing
Exceptions” on page 176 ) the exception. If the CATCH block for NE rethrows the
exception, then both CATCH blocks will be executed.
dcl NewException NE;
176
Chapter 10
•
Handling Exceptions
dcl SubException NEsub;
do;
do;
NEsub = _new_ SubException('Exception in method m');
NEsub.SecondaryMessage = "There's no code in m!";
throw NEsub;
catch NE;
put NE.getMessage();
/* Print exception information. */
call putlist(NE.traceback);
put NE.SecondaryMessage=;
/* Print secondary message. */
/* Could rethrow the NEsub exception if needed. */
endcatch;
end;
/* The following CATCH block will not be executed */
/* unless the CATCH block for NE rethrows the exception. */
catch NEsub;
...code to process NEsub exceptions...
endcatch;
end;
Catching and Rethrowing Exceptions
Each entry in the stack can process an exception and then pass it back up the stack by
rethrowing it, which allows the calling entry to perform additional processing. Each
entry can perform whatever processing is relevant to that entry.
do;
catch e1;
...process the exception...
throw e1; /* Rethrow the exception. */
endcatch;
end;
Note: If an exception is rethrown within a CATCH block, no CATCH block within the
same scope can recatch the exception. The exception is passed out of the scope
where it was thrown.
If SCL finds a second CATCH block for E1 within the same SCL entry but outside of
the scope of the DO group where the exception was thrown, then execution continues
with that second CATCH block. If SCL does not find another CATCH block for E1 in
that same SCL entry, then the exception is passed up the stack to the calling entry.
Suppose you have defined the NewException class (see Example Code 10.1 on page
173 ) and the ThrowIt class (see Example Code 10.2 on page 173 ). The following
program section calls method M, which throws the exception NE. The two CATCH
blocks catch, rethrow, and recatch the exception.
init:
dcl ThrowIt TI = _new_ThrowIt();
dcl NewException NE;
do;
do;
TI.m();
Handling SCL Exceptions with CATCH and THROW
177
catch NE;
put 'caught it';
throw NE;
endcatch;
end;
catch NE;
put 'caught it again';
endcatch;
end;
return;
Note: You cannot define multiple CATCH blocks for the same exception within the
same scope.
Nested CATCH Blocks
You can nest CATCH blocks. For example, suppose you define the class W as follows:
class w;
m: method n:num;
do;
dcl e1 e1;
dcl e2 e2;
do;
if (n < 0) then throw _new_ e2();
else throw _new_ e1();
catch e2;
put 'caught inner e2';
do;
dcl e1 e1;
if (n<0) then throw _new_ e2();
else throw _new_ e1();
catch e1;
put 'caught inner e1';
endcatch;
end;
endcatch;
end;
catch e1;
put 'caught outer e1';
endcatch;
catch e2;
put 'caught outer e2';
endcatch;
end;
endmethod;
endclass;
If you invoke method M with a negative argument as in the following program section:
init:
dcl w w = _new_ w();
w.m(-2);
178
Chapter 10
•
Handling Exceptions
return;
then the output would be
caught inner e2
caught outer e2
The SCL Throwable and SCL Exception Classes
All exceptions are subclasses of the SCL Exception class, which is a subclass of the SCL
Throwable class. When an exception is thrown, SCL automatically stores the name of
the entry that throws the exception, the line number where the throw occurs, and the
stack traceback at the point of the throw. You can set the message attribute via the
constructor when an instance of the exception is created. You can use the getMessage
method to return the message.
Example Code 10.5
SCL Throwable Class
class SCLThrowable;
public string(32767) message;
public list traceback; /* stack traceback */
public string entry;
/* SCL entry name */
public num line;
/* line number */
SCLThrowable: public method s:string;
message = s;
endmethod;
getMessage: public method return=string;
return message;
endmethod;
endclass;
Example Code 10.6
SCL Exception Class
class SCLException extends SCLThrowable;
SCLException: public method /(state='o');
_super("SCLException");
endmethod;
SCLException: public method s:string /(state='o');
_super(s);
endmethod;
endclass;
179
Chapter 11
Using SAS Tables
Introduction to Using SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . 180
Accessing SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Assigning Librefs in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Opening SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Number of Open SAS Tables Allowed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
SAS Tables and the SCL Data Vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Access Control Levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
Specifying a Control Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
Reading SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
Linking SAS Table Columns And SCL Variables . . . . . . . . . . . . . . . . . . . . . . . . . 184
Determining a Column's Position in a SAS Table . . . . . . . . . . . . . . . . . . . . . . . . . 184
Using Table-Lookup Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Controlling Access to SAS Table Rows in SCL Programs . . . . . . . . . . . . . . . . . . . 186
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Permanently Subsetting Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Temporarily Subsetting Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Searching with WHERE versus LOCATEC or LOCATEN . . . . . . . . . . . . . . . . . 187
Searching Efficiently . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
Undoing WHERE Clauses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
Changing the Sequence of Reading Rows in SCL Programs . . . . . . . . . . . . . . . . . 188
Updating SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Appending Rows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Deleting Rows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Remaining Rows Not Renumbered . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Renumbering Rows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Closing SAS Tables in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Determining Attributes of SAS Tables and Columns in SCL Programs . . . . . . . 190
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Querying Attributes of SAS Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Querying Attributes of SAS Table Columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Defining New Columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
Performing Other SAS Table Operations in SCL Programs . . . . . . . . . . . . . . . . . 191
180
Chapter 11
•
Using SAS Tables
Preserving the Integrity of Table Data in SCL Programs . . . . . . . . . . . . . . . . . . . 192
Manipulating SAS Table Indexes in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . 193
Introduction to Using SAS Tables in SCL
Programs
SCL provides a group of features that can read or manipulate data stored in SAS tables.
For example, you may want an SCL program to update one or more SAS tables, based
on user transactions from a single user interface. For a data entry and retrieval system,
you may want to use a secondary table to supplement the primary table. You might use
the secondary table as a lookup table for sophisticated error checking and field
validation. In addition, you may want to manipulate SAS tables to perform tasks like the
following:
•
displaying table values in a window
•
creating a new table
•
copying, renaming, sorting, or deleting a table
•
indexing a SAS table.
Many functions that perform SAS table operations return a SAS software return code,
called sysrc. “Introduction to SAS System Return Codes” on page 781 contains a list of
return codes with a section for operations that are most commonly performed on SAS
tables. You can check for these codes to write sophisticated error checking for your SCL
programs.
The following sections describe the tasks that SCL programs can perform on SAS tables,
along with summary information about the SCL function or routine to use to perform
that task. The functions and routines are described in Chapter 13, “SAS Component
Language Dictionary,” on page 209.
Accessing SAS Tables in SCL Programs
Before an SCL program can access the values in a SAS table, a communication link
must be established between SAS software, the SAS tables, and the SCL program. You
link SAS software to the tables by assigning librefs to the data libraries in which the
SAS tables are stored. You complete the communication by linking the SAS tables and
the SCL program, using the OPEN function to open the SAS tables. (Some SCL
routines, such as CALL FSEDIT and CALL FSVIEW automatically open the SAS table
that they are displaying. Therefore, the OPEN function is not needed to open the
specified table.)
Assigning Librefs in SCL Programs
SCL provides the LIBNAME function for assigning a libref in an SCL program. You
can also assign librefs outside an SCL program that works with SAS tables by putting
the appropriate LIBNAME statement in the application's start-up file, the autoexec file.
Opening SAS Tables in SCL Programs
181
For more information about assigning librefs outside an SCL program, see the SAS
software documentation for your host operating system.
If you have SAS/SHARE software or SAS/CONNECT software installed at your
location, you can also use Remote Library Services (RLS) to assign librefs. RLS gives
your SCL applications “read” or “write” access to SAS tables, views and catalogs across
hardware platforms and SAS releases. Once an RLS libref is established, the RLS
functionality is transparent to SAS tables and views in SCL programs. Catalog
compatibility across platforms is architecture dependent. For further information, see
SAS/SHARE User's Guide.
Opening SAS Tables in SCL Programs
Introduction
To open a SAS table, use the OPEN function. Opening a SAS table provides the gateway
through which an SCL program and a SAS table can interact. This process does not
actually access the information in a SAS table, but it makes the table available for the
program's use. To access the data in the SAS table, the program must perform “read”
operations on the table. When you open a SAS table, the following actions take place:
•
The SAS table data vector (TDV) for the table is created to store copies of the table's
column values.
•
A unique numeric identifier is assigned to the SAS table. This identifier is used by
other functions that manipulate data.
•
An access control level is assigned to the SAS table. This control level determines
the level of access to the SAS table that is permitted to other users or applications
that try to use the SAS table at the same time.
The identifier number identifies the table to the application, and you pass it to other SCL
functions that manipulate the SAS table. Because this number is unique for each table
that is currently open, it is useful for tracking multiple SAS tables that are open at the
same time.
Note: If for some reason a SAS table cannot be opened, the OPEN function returns a
value of 0 for the table identifier. Therefore, to determine whether a SAS table has
been opened successfully, you should test the value of the return code for the OPEN
function in your SCL program. Doing this ensures that you don't cause a program to
halt by passing a 0 to another function that uses that SAS table identifier. To
determine why the table could not be opened, use the SYSMSG function to retrieve
the message that is associated with the return code.
Number of Open SAS Tables Allowed
An application can have a maximum of 999 SAS tables open simultaneously. However,
your operating system may impose other limits. For details, see the documentation
provided by the vendor for your operating system.
Although SCL permits you to have a large number of tables open simultaneously, be
aware that memory is allocated for each SAS table from the time the SAS table is
opened until it is closed. Therefore, try to minimize the number of tables that are open at
the same time, and close them as soon as a program finishes with them for that session.
182
Chapter 11
•
Using SAS Tables
SAS Tables and the SCL Data Vector
Introduction
When an application opens a SAS table, its TDV is empty. However, to enable the
program to work with the SAS table columns, SCL provides functions for copying table
rows one at a time from the SAS table to the TDV. Once column values for a row are in
the TDV, you can copy these values into the SCL data vector (SDV), and the application
can manipulate the column values.
Before you can display or manipulate the values of SAS table columns, those columns
must be linked to SCL variables through the TDV and the SDV. Special SCL functions
and storage locations facilitate the transfer of values between SAS table columns and
SCL variables. Figure 11.1 on page 182 illustrates the SDV and TDV that are created
for an application that opens a SAS table. This figure shows the paths that rows take
when they are read from the table, displayed in the window, processed, and then returned
to the table.
Figure 11.1
Path of Data in SAS Table Read and Write Operations
SAS Table
UPDATE
APPEND
REFRESH
RETURN
Application
Window
Fields
SCL Data Vector
(SDV)
Table Data Vector
(TDV)
FETCH/FETCHOBS
LOCATEC/LOCATE
ENTER
END
CANCEL
SET
GETVARC/N
***
***
***
System Window, Nonwindow, and Special
Variables
Variables
PUTVARC/N
***
Variables
Two steps are required in order to transfer data from an open SAS table to an SCL
program:
1. The values of the columns in a row in the open SAS table are copied into the TDV.
2. The values of the columns in the TDV are copied to the SDV, which contains all of
the SCL variables (window variables, nonwindow variables, system variables, and so
on). The transfer of data from the TDV to the SDV can be either automatic (when the
SET routine is used) or under program control (when the GETVARC or GETVARN
functions are used).
Reading SAS Tables in SCL Programs
183
Once the values are in the SDV, you can manipulate them by using SCL statements.
Two steps are also required in order to transfer data from an SCL program to an open
SAS table:
1. The column values in the SDV are transferred to the TDV. The transfer of data from
the SDV to the TDV can be either automatic (when the SET routine is used) or under
program control (when PUTVARC or PUTVARN is used).
2. The values in the TDV are written to the columns in a row in the open table.
Access Control Levels
When a SAS table is opened, SAS software determines the control level for the table.
The control level determines the extent to which access to the table is restricted. For
example, an application may be able to gain exclusive update access to the entire SAS
table, or it may be able to gain exclusive update access to only the row that is currently
in use. In either case, there are ramifications for any users or applications that need to
access the SAS table at the same time. You can open a SAS table with one of the
following control levels:
RECORD
provides exclusive update access only to the SAS table row that is currently in the
TDV (as with the FETCH and FETCHOBS functions). With this control level, the
same user can open the same SAS table multiple times (multiple concurrent access).
In addition, if SAS/SHARE software is used, then multiple users can open the same
SAS table simultaneously for browsing or for editing. For more information, see
SAS/SHARE User's Guide.
MEMBER
provides exclusive update access to an entire SAS table. While this control level is in
effect, no other user can open the table, and the same user cannot open the table
multiple times.
Specifying a Control Level
When you use the OPEN function to open a SAS data set in UPDATE mode, by default
the table is opened with RECORD-level control. However, in SCL you can use the
OPEN function with the SAS data set option CNTLLEV= to set the control level when a
SAS table opens. See “OPEN” on page 574 for more information.
Reading SAS Tables in SCL Programs
Introduction
You may want to use an SCL program to manipulate column values from SAS tables.
For example, you may want to do one or more of the following:
•
display data values in a window
•
use the values in arithmetic calculations
•
determine data values before taking certain actions.
184
Chapter 11
•
Using SAS Tables
Before a program can manipulate the data, it must read the data from the table. After
column values are changed, the program can update the values of columns in the table.
In addition to updating existing column values, programs also can add new rows or
delete obsolete rows.
After a SAS table is open, you can access any column value for any row in the SAS
table. The first step in accessing the data involves reading (or copying) a row from the
SAS table to the TDV—for example, by using the FETCH function. By default, the
FETCH function starts with the first row in the SAS table and reads the next row from
the SAS table each time it executes.
Linking SAS Table Columns And SCL Variables
Introduction
The next step in accessing the data is to link the SAS table columns in the TDV with the
SCL window variables and nonwindow variables in the SDV. The function that you use
depends on whether the SCL variables and SAS table columns have the same name and
type. If an application has some SCL variables that match SAS table columns and others
that do not, then you can use a combination of these techniques.
Matched Column and Variable Names
If columns of a SAS table and SCL variables have the same names and types, then you
can use the SET routine to link all of them automatically with a single program
statement. The SET routine is typically invoked immediately following the OPEN
function.
Note: If you use the SET routine and then also use the PUTVARC or PUTVARN
routine for an SCL variable that has a matching SAS table column, the SET routine
overrides the PUTVARC or PUTVARN routine. Doing this is inefficient because
duplicate actions are performed.
Unmatched Column and Variable Names
When the SCL variables do not have the same names or types as SAS table columns,
you must use a GETVARC or GETVARN statement (for character and numeric values,
respectively) for each unmatched column to link them from the TDV to the SDV. Once
the columns have been manipulated, use an individual PUTVARC or PUTVARN
routine to link each one from the SDV back to the TDV.
Note: The GETVARC and GETVARN functions establish only a temporary link
between a SAS table column and an SCL variable. When the statement executes, the
columns are linked. After the statement executes, the link is terminated. Therefore,
you must use the GETVARC or GETVARN function one time for each SAS table
column that you want to link. This is different from the SET routine, which
establishes a permanent link between any matching SAS table and SCL variables
until the open SAS table is closed.
Determining a Column's Position in a SAS Table
Some functions, such as GETVARC, GETVARN, PUTVARC and PUTVARN, require
the position of a column in the SAS table row. Use the VARNUM function to determine
the position, and then use the position repeatedly throughout your program. The
following example uses the VARNUM function to determine the position of several
columns. After the column positions have been determined, the program links to a
labeled section called GETVALUE to determine the column values.
Reading SAS Tables in SCL Programs
185
INIT:
control enter;
houses=open('sasuser.houses','u');
if (houses=0) then _msg_=sysmsg();
else
do;
vtype=varnum(houses,'style');
vsize=varnum(houses,'sqfeet');
vbedrms=varnum(houses,'bedrooms');
vbathrms=varnum(houses,'baths');
vaddress=varnum(houses,'street');
vcost=varnum(houses,'price');
link getvalue;
end;
return;
MAIN:
...more SCL statements...
return;
TERM:
if (houses>0) then rc=close(houses);
return;
GETVALUE:
rc=fetch(houses);
type=getvarc(houses,vtype);
size=getvarn(houses,vsize);
bedrms=getvarn(houses,vbedrms);
bathrms=getvarn(houses,vbathrms);
address=getvarc(houses,vaddress);
cost=getvarn(houses,vcost);
return;
Using Table-Lookup Techniques
Table lookup, the process of looking up data in a data structure, has several useful
applications for data entry applications. For example, you may want to display certain
information in a window based on a value that a user has entered. If this information is
stored in another SAS table, then you can use table-lookup techniques to read and
display this information. In addition, you can use table lookup to perform field validation
by ensuring that a value entered by a user is a value that is contained in a specified SAS
table.
To validate a field value, you can use the LOCATEC, LOCATEN, or WHERE function
to search a secondary SAS table for a specific character or numeric value that has been
entered by a user. For example, you might want to make sure that users enter names that
exist in another SAS table. You also can use these techniques to display text from a
secondary SAS table, based on values that users enter in the fields. For example, when a
user enters a valid name in the Employee Name field, you can look up the associated
sales region and sales to date in the secondary SAS table and then display this
information in the window.
186
Chapter 11
•
Using SAS Tables
Controlling Access to SAS Table Rows in SCL
Programs
Introduction
For many applications, you may want an SCL program to read from a SAS table only the
rows that meet a set of search conditions. For example, if you have a SAS table that
contains sales records, you may want to read just the subset of records for which the
sales are greater than $300,000 but less than $600,000. To do this, you can use WHERE
clause processing, which is a set of conditions that rows must meet in order to be
processed. In WHERE clause processing, you can use either permanent or temporary
WHERE clauses.
Permanently Subsetting Data
A permanent WHERE clause applies a set of search conditions that remain in effect until
the SAS table is closed. You might use a permanent WHERE clause to improve the
efficiency of a program by reading only a subset of the rows in a SAS table. You might
also want to use a permanent WHERE clause in applications when you want to limit the
SAS table rows that are accessible, or visible, to users. For example, if you are working
with a large SAS table, users may not need access to all the rows to use your application.
Or, for security reasons, you may want to restrict access to a set of rows that meet certain
conditions.
SCL provides several features that enable you to subset a SAS table based on specified
search conditions. To apply a permanent WHERE clause to a SAS table, you can use the
SAS data set option WHERE= with the OPEN function. For example, the following
WHERE clause selects only the records for which the sales are greater than $300,000 but
less than $600,000:
/* Open the SAS table and display a */
/* subset of the SAS table rows
*/
salesid=open
("sample.testdata(where=((sales > 300000)"||
"and (sales < 600000)))",'i');
You can also use the WHERE= option in SCL with the FSEDIT and FSVIEW routines.
Temporarily Subsetting Data
In addition to restricting access to SAS table rows, you may want to enable users to
subset the accessible records even further. In this case, you can use the WHERE function
to apply a temporary WHERE clause. A temporary WHERE clause applies a set of
search conditions that can be modified or cancelled by subsequent SCL statements. For
example, you could apply a temporary WHERE clause like the following:
rc=where(dsid,'SSN='||ssn);
When a SAS table is indexed, you can use the SETKEY function for subsetting. For
example, if a SAS table is indexed on the column SSN, you could use:
rc=setkey(dsid,'SSN','eq');
Controlling Access to SAS Table Rows in SCL Programs
187
Searching with WHERE versus LOCATEC or LOCATEN
You can search efficiently with the WHERE function if you are working with a large
SAS table that is indexed by the column or columns for which you are searching. It is
also appropriate to use the WHERE function when you are using an expression that
involves several columns to locate rows.
However, you can use LOCATEC or LOCATEN to find a row when one or more of the
following conditions are met:
•
The SAS table is small.
•
You are searching for one row that meets a single search condition (for example, the
row that contains a particular name).
•
You are looking for one row that meets a single search condition in a large SAS
table, if the SAS table is sorted by the column for which you are searching, and if
you are using the more efficient binary search. See the following section for more
information.
Searching Efficiently
By default, LOCATEC and LOCATEN search a SAS table sequentially. However, a
sequential search is not always the most efficient way to locate a particular row,
especially if your SAS table has been sorted. If a SAS table has already been sorted by
the column for which you want to search, you can specify a faster, more efficient binary
search. For a binary search, use an additional optional argument with LOCATEC or
LOCATEN to specify the order in which the SAS table has been sorted (A for ascending
order or D for descending order). For example, assuming that the SAS table
MYSCHOOL.CLASS has been sorted in ascending order by NAME, you can use the
following statements to perform a binary search:
dsid=open('myschool.class');
vnum=varnum(dsid,'name');
sname='Gail';
val=locatec(dsid,vnum,sname,'a');
Undoing WHERE Clauses
WHERE clauses impose certain restrictions on other SCL functions that manipulate
data. Therefore, in some cases, you may need to undo a WHERE clause in an SCL
program before using other functions. When you specify a WHERE clause, the WHERE
conditions replace the conditions that were specified in the previous WHERE clause.
However, you can augment a WHERE condition with the ALSO keyword. For example,
the following WHERE clause adds the condition of "age greater than 15" to an existing
WHERE clause:
rc=where(dsid,'also age > 15');
To undo the condition that was added by the ALSO keyword, you could use the
following statement:
rc=where(dsid,'undo');
To undo (or delete) a temporary WHERE clause, use the WHERE function and specify
only the SAS table identifier argument. This process undoes all temporary WHERE
clauses that are currently in effect.
188
Chapter 11
•
Using SAS Tables
Changing the Sequence of Reading Rows in SCL
Programs
When an application displays a subset of a SAS table, you may want to let users display
and scroll through all rows that meet the search conditions. To do this, you can use a set
of SCL functions that reread table rows. For example, when a program displays the first
row that meets the conditions, SCL provides functions that you can use to mark the row.
Then a user can continue to search the rest of the SAS table for any other rows that meet
the search conditions, counting them along the way. After finding the last row that meets
the search conditions, the user can redisplay the first row in the subset (the row that was
marked earlier). The following sequence of steps implements this technique:
1. Use the NOTE function to mark a row in the subset for later reading.
2. Use the POINT function to return to the marked row after you have located all rows
that meet the search conditions.
3. Use the DROPNOTE function to delete the NOTE marker and free the memory used
to store the note after the program finishes using the noted row.
Updating SAS Tables in SCL Programs
Introduction
When a table row is read, its data follow a path from the SAS table through the TDV to
the SDV, where finally they can be manipulated. After the data is manipulated, it must
follow the reverse path from the SDV through the TDV back to the SAS table. If you use
the SET routine to link the values from the TDV to the SDV, then any changed values
are automatically linked from the SDV back to the TDV. If you do not use SET, then
you must explicitly copy the value of each variable to the TDV. In either case, you use
the UPDATE function to copy the values from the TDV to the SAS table.
Appending Rows
To add new rows to a SAS table rather than updating the existing rows, use the
APPEND function. If the SCL variables have the same name and type as the SAS table
columns and you use the SET routine to link them, then using the APPEND function is
straightforward, and the values are automatically written from the TDV to the SAS table.
Note: If the program does not use the SET routine, or if the APPEND function is used
with the NOSET option, a blank row is appended to the SAS table. This is a useful
technique for appending rows when the SCL program or the window variables do not
match the SAS table columns. For example, when the SET routine is not used, you
would use a sequence of statements like those below to append a blank row and then
update it with values.
rc=append(dsid);
...PUTVARC or PUTVARN program statement(s)...
rc=update(dsid);
Updating SAS Tables in SCL Programs
189
Deleting Rows
To delete rows from a SAS table, use the DELOBS function. In order to use this
function, the SAS table must be open in UPDATE mode. The DELOBS function
performs the following tasks:
•
marks the row for deletion from the SAS table. However, the row is still physically
in the SAS table.
•
prevents any additional editing of the row. Once a row has been marked for deletion,
it cannot be read.
Remaining Rows Not Renumbered
Although deleted rows are no longer accessible, all other rows in the SAS table retain
their original physical row numbers. Therefore, it is important to remember that a row's
physical number may not always coincide with its relative position in the SAS table. For
example, the FETCHOBS function treats a row value as a relative row number. If row 2
is marked for deletion and you use FETCHOBS to read the third row, FETCHOBS reads
the third non-deleted row—in this case, row 4. However, you can use FETCHOBS with
the ABS option to count deleted rows.
Non-deleted rows are intentionally not renumbered so that you can continue to use row
numbers as pointers. This is important when you are using the FSEDIT procedure or
subsequent SAS statements that directly access table rows by number, such as the
POINT= option in a SAS language SET statement.
You can control row renumbering if necessary. See the next section for details.
Renumbering Rows
To renumber accessible SAS table rows, an SCL program must use one of the following
techniques to process the SAS table:
•
Sort the table, using either the SORT function in SCL or the SORT procedure. If the
SAS table is already in sorted order, then you must use the FORCE option.
Note: The SORT function and PROC SORT do not sort and replace an indexed SAS
table unless you specify the FORCE option, because sorting destroys indexes for
a SAS table.
•
Copy the table, using either the COPY function in SCL or the COPY procedure. In
this case, the input and output tables must be different. The output table is the only
one that is renumbered.
•
Read the remaining data table rows, using the SAS language SET statement in a
DATA step (not the SCL SET statement), and write these rows to a data table. To
avoid exiting from SCL, you can use a submit block. For example:
houseid=open('sasuser.houses','u');
...SCL statements that read rows and delete rows...
submit continue;
data sasuser.houses;
set sasuser.houses;
run;
endsubmit;
190
Chapter 11
•
Using SAS Tables
Closing SAS Tables in SCL Programs
After an SCL program has finished using a SAS table, the program should close the
table with the CLOSE function at the appropriate point in your program. If a SAS table
is still open when an application ends, SAS software closes it automatically and displays
a warning message. In general, the position of the CLOSE function should correspond to
the position of the OPEN function, as follows:
•
If the OPEN function is in the initialization section, then put the CLOSE function in
the termination section.
•
If the OPEN function is in MAIN, then put the CLOSE function in MAIN.
Note: If you're designing an application system in which more than one program uses a
particular SAS table, and if the identifier for this table can be passed to subsequent
programs, then close the SAS table in the termination section of the program that
uses the table last.
Determining Attributes of SAS Tables and
Columns in SCL Programs
Introduction
SCL provides features for determining characteristics (or attributes) of the SAS table or
columns with which a program is working. For example, one approach is to open a table,
determine how many columns are in the table, and then set up a program loop that
executes once for each column. The loop can query the attributes of each column. To do
this, the program needs to determine how many columns are in the SAS table, as well as
the name, type, length, format, informat, label, and position of each column.
Querying Attributes of SAS Tables
SAS tables have a variety of numeric and character attributes associated with them.
These attributes can provide some basic information to your SCL program. For example,
to determine the number of columns in an existing SAS table, use the NVARS argument
with the ATTRN function. For a list of other table attributes and how to retrieve them,
see “ATTRC and ATTRN” on page 226.
Querying Attributes of SAS Table Columns
Columns in a SAS table also have several attributes that your program may need to
query. Here is a list of column attributes and the SCL functions that you can use to
retrieve those attributes:
Table 11.1
name
SAS Column Attributes and the SCL Functions to Query Them
VARNAME function
Performing Other SAS Table Operations in SCL Programs
number
VARNUM function
data type
VARTYPE function
length
VARLEN function
label
VARLABLE function
format
VARFMT function
informat
VARINFMT function.
191
Defining New Columns
After determining the name, type, length, label, format, and informat of each column,
you can add a new column that has these attributes to the column list for a new SAS
table. To do this, first use the OPEN function with the N argument (for NEW mode), and
then use the NEWVAR function.
CAUTION:
Your program should check to see whether the SAS table exists before opening
it in NEW mode. When used with the N argument (for NEW mode), the OPEN
function replaces an existing SAS table that has the same name. If you do not want to
delete an existing SAS table by opening it in NEW mode, then use the EXIST
function to confirm that the table does not exist before using OPEN to create a new
SAS table.
Performing Other SAS Table Operations in SCL
Programs
There are other SCL functions that you can use to perform operations on SAS tables.
The tasks that you can perform, along with the function to use, are as follows:
•
To copy a table, use the COPY function. By default, if the target file already exists,
the COPY function replaces that file without warning. To avoid unintentionally
overwriting existing files, your program should use the EXIST function to determine
whether the target file exists before executing the COPY function. (You can use
COPY with a WHERE clause to create a new table that contains a subset of the rows
in the original table.)
•
To create a new table, use the OPEN function with the N option. (The table must be
closed and then reopened in UPDATE mode if the program will update it). Then, use
NEWVAR to create columns.
•
To enable users to create a new table interactively, use the NEW function.
•
To enable users to create a new table interactively from an external file, use the
IMPORT function or the IMPORT wizard.
•
To delete a table, use the DELETE function. (The table must be closed).
•
To rename a table, use the RENAME function. (The table must be closed.)
192
Chapter 11
•
Using SAS Tables
•
To sort a table, use the SORT function. (The table must be open in UPDATE mode.)
Preserving the Integrity of Table Data in SCL
Programs
SCL provides a group of functions that specify and enforce integrity constraints for SAS
tables. Integrity constraints preserve the consistency and correctness of stored data, and
they are automatically enforced for each addition, update, and deletion activity for a SAS
table to which the constraints have been assigned. For such a table, value changes must
satisfy the conditions that have been specified with constraints.
There are two basic types of integrity constraints: general constraints and referential
constraints. The following list shows the specific types of integrity restraints that you
can apply through SCL. The first four items are general constraints, which control values
in a single SAS table. The last item is a referential constraint, which establishes a parentchild relationship between columns in two or more SAS tables.
•
A column can contain only non-null values.
•
A column can contain only values that fall within a specific set, range, or list of
values, or that duplicate a value in another column in the same row.
•
A column can contain only values that are unique.
•
A column that is a primary key can contain only values that are unique and that are
not missing values.
•
A column that is a foreign key (the child) can contain only values that are present in
the associated primary key (the parent) or null values. A column that is a primary
key can contain only values that cannot be deleted or changed unless the same
deletions or changes have been made in values of the associated foreign key. Values
of a foreign key can be set to null, but values cannot be added unless they also exist
in the associated primary key.
SCL provides the following functions for creating and enforcing integrity constraints:
ICCREATE
creates and specifies integrity constraints for a SAS table.
ICDELETE
drops an integrity constraint.
ICDESCRIBE
obtains the attributes for all existing integrity constraints within a SAS table. You
can also obtain integrity constraint information using the CONTENTS procedure.
ICTYPE
returns the type of constraint that is assigned to a SAS table.
ICVALUE
returns the varlist or WHERE clause that is associated with an integrity constraint.
For more information about integrity constraints, see “Understanding Integrity
Constraints” in Chapter 26 of SAS Language Reference: Concepts.
Manipulating SAS Table Indexes in SCL Programs
193
Manipulating SAS Table Indexes in SCL Programs
When you develop an application that creates a SAS table, you may want to give users
the option of creating an index for the table. An index, which provides fast access to
rows, is an auxiliary data structure that specifies the location of rows, based on the
values of one or more columns, known as key columns. Both compressed and
uncompressed SAS tables can be indexed by one or more columns to aid in the
subsetting, grouping, or joining of rows. SAS table indexes are particularly useful for
optimizing WHERE clause processing.
SCL provides a set of functions for creating and manipulating SAS table indexes.
However, SCL functions are just one way of building and querying SAS table indexes.
Other ways include:
•
the DATASETS procedure in Base SAS software
•
the INDEX= option (when you are creating a SAS table)
•
the SQL procedure in Base SAS software.
There are two types of indexes: simple indexes and composite indexes. A simple index is
an index on a single column, and a composite index is an index on more than one
column. A SAS table can have multiple simple indexes, multiple composite indexes, or a
combination of simple and composite indexes.
SCL provides the following functions for manipulating indexes:
ICREATE
creates an index for SAS tables that are open in UTILITY mode.
IVARLIST
returns a list of one or more columns that have been indexed for the specified key in
the table.
ISINDEX
returns the type of index for a column in a SAS table, as follows:
BOTH
The column is a member of both simple and composite indexes.
COMP
The column is a member of a composite index.
REG
The column is a member of a regular (simple) index.
(blank)
No index has been created for the specified column.
IOPTION
returns a character string that consists of the options for the specified key and index
columns. The options are separated by blanks.
IDELETE
deletes an index for a SAS table that is open in UTILITY mode. You can delete an
index when a program finishes with it, or if you find that the index is not operating
efficiently. Keep in mind that indexes are not always advantageous. Sometimes the
costs outweigh the savings. For a detailed discussion of when to use indexes, see the
information about SAS files in SAS Language Reference: Concepts.
194
Chapter 11
•
Using SAS Tables
195
Chapter 12
Using External Files
Introduction to Using External Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . 196
Accessing External Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Assigning Filerefs in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Opening Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Making an Open File Available to Other Programs . . . . . . . . . . . . . . . . . . . . . . . . 198
Number of Open Files Allowed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
File Data Buffers and SCL Data Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
Reading Values from External Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . 199
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Order of Reading Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
Reading Record Values into the SDV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
Reading Records as Separate Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
Identifying a Value's Starting Column . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
Modifying External Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
Writing Modified Records or New Records to a File . . . . . . . . . . . . . . . . . . . . . . . 201
Closing Files in SCL Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
Changing the Sequence of Reading Records in SCL Programs . . . . . . . . . . . . . . . 202
Other Ways SCL Interacts with External Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Determining Attributes and Attribute Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Determining Information about an FDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Renaming and Deleting an External File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Reading and Modifying Files in the Same Directory with SCL . . . . . . . . . . . . . . . 204
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
Determining the Number of Files in a Directory . . . . . . . . . . . . . . . . . . . . . . . . . . 204
Finding the Names of Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
Manipulating Files in an Open Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
Opening Files in an Open Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Closing Files in an Open Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Changing All the Files in a Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Creating a Subdirectory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Closing a Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Other Manipulations for Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
196
Chapter 12
•
Using External Files
Introduction to Using External Files in SCL
Programs
In addition to using SCL to manipulate SAS tables, you can use it to manipulate external
files. External files are files that are created and maintained on a host operating system
(for example, files that you have created with your system editor or files in which you
have stored the output of SAS procedures). They have different internal formats than
SAS files.
When you use external files to store data or other information, you can use SCL
functions to read, update, and write information to new files, and to perform utility
operations on existing files. These functions enable you to create SCL programs that do
the following:
•
read values from external files for field validation
•
manipulate data values that your site maintains in external files
•
write information in a form that can be read by applications that were created with
the software of other vendors.
Note: Your operating system maintains groups of files in an aggregate storage location.
Your operating system may identify these locations with different names (for
example, directory, folder, subdirectory, partitioned data set, or MACLIB). If you
need more information, see the SAS documentation for your operating environment.
Ordinarily, you must use a logical name called a fileref to identify the location of an
external file to SAS software. SCL allows you to assign a fileref to a directory and then
to open and perform operations on as many of its files as the program requires.
Many functions that perform external file operations return a SAS system return code,
called sysrc. “Introduction to SAS System Return Codes” on page 781 contains a list of
return codes with a section for operations that are commonly performed on external files.
You can check for these codes to write more sophisticated error checking for your SCL
programs.
Accessing External Files in SCL Programs
Before SCL programs can work with external files, you must establish a communication
link between SAS software, the file, and your SCL program. You start the
communication link by assigning a fileref to the file, which links the file to SAS
software. You complete the communication link by using an SCL function to open the
file, which links the file to the SCL program. SCL also enables you to establish this
communication link between SAS software, a directory, and your SCL program. Your
program can then use any file in that directory without assigning a fileref to it. This can
make it easier for you to process multiple files in the same directory.
Opening Files in SCL Programs
197
Assigning Filerefs in SCL Programs
To establish the communication between SAS software and an external file, you must
assign a fileref to the file with the FILENAME function. If an application requires that
users specify the name of the physical file, then create a block of SCL code labeled with
a window variable name to run only when a user enters a filename in that field. You can
also put the FILENAME function in the MAIN section so that it executes after a user
specifies the filename. In this case, add a statement to check that the field containing the
filename has been modified so that the FILENAME function does not run every time the
MAIN section runs. When a program can specify the name of the physical file without
user input, put the function in the initialization section so that the function executes only
once, before the window opens.
You can also assign filerefs outside of an application when files are used by all or large
parts of your application. You assign filerefs to these files by using the FILENAME
statement in Base SAS in the application's start-up file (the autoexec file). For more
information about assigning filerefs, see the SAS documentation for your operating
environment.
There are other SCL functions that you can use to manipulate filerefs. Use these
functions to prevent programs from terminating prematurely because of possible errors
(for example, a fileref is already assigned or a physical file does not exist).
•
Use the FILEREF function to verify that a fileref has been assigned to a physical file
for the current SAS session or process.
•
Use the FEXIST function to verify that the file associated with a specified fileref
exists.
•
Use the FILEEXIST function to verify that the file associated with a physical name
exists.
Opening Files in SCL Programs
Introduction
To complete the communication link between an application and an external file, use the
FOPEN function to open the file. Opening a file does not access the information in the
file. It simply makes the file available to the program.
When you open an external file, a unique identifier is assigned to the external file. This
identifier is used by any other SCL functions that manipulate the file. In addition, a
temporary storage buffer is automatically created for the external file. This storage area
is used to store copies of file records.
The FOPEN function returns the program's identification number for that file. This
unique number is called the file identifier. You use this identifier by storing it in an SCL
variable and passing the variable name as an argument to all the SCL functions that
manipulate that file or directory. This technique enables you to open and manipulate
multiple files at the same time and to clearly identify which file to manipulate.
When you open a file, you specify an open mode. The open mode determines the actions
that can be performed on the file. With the FOPEN function, you can also specify the
198
Chapter 12
•
Using External Files
file's record length. If you specify a record length of 0, the existing record length is used.
For details about the modes and record lengths and how to specify them, see “FOPEN”
on page 401.
Making an Open File Available to Other Programs
After you open an external file, its contents are available to all programs in your
application. However, you must link the file to the programs by using one of the
following techniques to pass them the variable that contains the file identifier.
•
You can pass the file identifier as a parameter to other programs by using the
parameter-passing mechanism of the DISPLAY or METHOD routine with the
ENTRY or METHOD statement. This is the preferred method.
•
You can store the file identifier value by using the SETPARMID routine, and you
can retrieve it by using the GETPARMID function. This method limits you to
passing only one file identifier at a time.
•
You can pass the file identifier value as a macro variable by using the SYMPUTN
routine, and you can retrieve it by using the SYMGETN function.
•
You can pass the file identifier as an item in the local environment list. For details
about this list, see “Introduction to SCL Lists” on page 54.
Number of Open Files Allowed
SCL allows a maximum of 999 external files to be open simultaneously in an
application. However, your operating system may impose other limits. For further
details, refer to the documentation provided by the vendor for your operating system.
Although SCL allows you to have a large number of files open simultaneously, you
should be aware that memory is allocated for each file from the time the file is opened
until it is closed. Therefore, you should try close files as soon as your program is
finished with them.
File Data Buffers and SCL Data Vectors
When an SCL program starts executing, an SCL Data Vector (SDV) is created for the
program. The SDV contains temporary storage areas for the program's SCL variables.
Values of program variables are manipulated and stored in the SDV before they are
written to or deleted from an external file. When an external file is opened, a temporary
storage buffer called the file data buffer (FDB) is created for it. The FDB is the length of
the file's records, and it is empty until a record is read from the file. A “read” function
copies a record from the file into the FDB. A “write” function moves the contents of the
FDB to a record in the physical file and clears the file's FDB. Once a record is in the
FDB, it remains there until the record is written back to the file, until another record is
read in, or until the file is closed.
Figure 12.1 on page 199 illustrates the SDV and the FDB for an application that uses an
external file. This figure shows the paths that file records take when they are read from
the file, displayed in the window, processed, and then returned to the file.
Reading Values from External Files in SCL Programs
Figure 12.1
199
Path of Data in File Read and Write Operations
External File
FWRITE
FAPPEND
REFRESH
RETURN
Application
Window
Fields
FREAD
ENTER
END
CANCEL
SCL Data Vector
(SDV)
File Data Buffer
(FDB)
FGET
***
***
***
FPUT
System Window, Nonwindow, and Special
Variables
Variables
Record
Reading Values from External Files in SCL
Programs
Introduction
Before an SCL program can use the information in an external file, the program must
read the file's records. For example, an application may need to use external file records
to do the following:
•
display the values for users to browse or edit
•
modify existing values
•
add new values or records
•
delete values or records.
In order to read record values from the external file, your SCL program must first copy a
record from the file into the FDB. Then it must copy the contents of the FDB into the
SDV to make the values available to your SCL program. A value can be either part of a
record or an entire record. Unless you must read values separately for some reason,
reading an entire record as a single value is the easier technique to use. To complete the
process of reading values from an open file, follow these steps:
1. A record must be copied from the file to the FDB. Use the FREAD function to copy
the values to the FDB, starting at the file's first record and reading each record
sequentially.
200
Chapter 12
•
Using External Files
2. Each value in the record must be copied from the FDB to the SDV, where the value
can be used by the application. Use the FGET function to copy the contents of the
FDB (interpreted as values) to the SDV.
Order of Reading Records
Many types of external files can be read only sequentially, from the first record to the
last. However, when a file supports random access, you can use SCL functions to change
that sequence and either reread a particular record or start at the first record and reread
the entire file. For more information, see “Changing the Sequence of Reading Records in
SCL Programs” on page 202.
Reading Record Values into the SDV
When the FGET function reads values from the FDB into the SDV, it makes the contents
of the FDB available to the SCL program. You can control how this step processes the
contents of the FDB by reading the FDB contents either as one single value or as a series
of separate values. Reading the contents of the FDB as a single value can simplify your
program. To do this, you can design a single control or field in the window to display the
entire contents of the record. If you need to read record values into separate window
variables, you can read the FDB contents as a single value into a program variable in the
SDV. Then, you can use SAS character functions (like SCAN or SUBSTR) to assign
parts of that program variable to window variables. The following example finds the
length of a record and then reads the entire record as a single value into the window
variable ROW.
length=finfo(fileid,'lrecl');
reclen=inputn(length,'best.');
rc=fget(fileid,row,reclen);
If ROW is a nonwindow variable instead of a window variable, then values that are read
from the FDB are in the SDV, but they are not displayed in the window until they are
assigned to a window variable.
Note: The code in the preceding example is host specific. See the SAS documentation
for your operating environment for more information.
You determine whether the contents are treated as one value or as a series of values.
There is a column pointer in the FDB that is set to 1 when the contents are read. By
default, the FGET function copies the value from the current position of the column
pointer to the next separator character. The default separator character is one blank.
Therefore, the default action of the FGET function is to copy the value from the current
position of the column pointer to the next blank. (To designate a different character as
the separator character, use the FSEP function).
After each FGET function, the column pointer is positioned one column past the last
character that was read. When the FDB contains no more values, the FGET function
returns −1 to signal that it has reached the end of the FDB.
Reading Records as Separate Values
Reading the contents of the FDB as a series of separate values brings up a different set of
considerations. Your applications must process a specified number of file values and
display them in window variables of a particular size. Also, in order to read separate
values, you need to know more about the external files that your application will
process. You need to know how many values a record contains, and it is helpful if you
Modifying External Files in SCL Programs
201
know the starting columns for the values or the characters that separate the values.
Finally, you need to define separate controls or fields to display the values.
When you read the FDB contents as separate values, you can locate these values by
positioning the FDB column pointer at the column where the value begins or by
specifying the character that separates these values. By default, the separator character
for file records is a blank.
Identifying a Value's Starting Column
When you know the numbers of the columns where the values start, you can use the
FPOS function to move the “read” pointer to the column where the next value begins.
When the FPOS and FGET functions are used together, the FPOS function sets the
starting column for the FGET function, which reads the FDB contents up to the next
separator character unless a length is specified.
The following example shows how to read separate values when you know the numbers
of the columns where the values start. This example reads record values into the
variables NAME, HEIGHT, and WEIGHT by using the FPOS function to specify the
position of the “read” pointer.
rc=fget(fileid,name,20);
rc=fpos(fileid,21);
rc=fget(fileid,height);
rc=fpos(fileid,28);
rc=fget(fileid,weight);
Modifying External Files in SCL Programs
Introduction
An application can enable users to modify the values in external files interactively.
External files can be modified by updating existing records, by adding new records, or
by deleting records. To store record values in external files, you can use functions to
update the FDB with values that are stored in window variables or program variables.
When you write the contents of the FDB to a file, you can update an existing record, or
you can append the record at the end of the file.
Writing Modified Records or New Records to a File
In order to return values to a file that is open for writing, an application must do the
following:
1. Write each value from a window or program variable. Use the FPUT function to
copy values from the SDV to the FDB.
2. Write record values from the FDB to the external file. Use the FWRITE or
FAPPEND function to write the current values to the external file and to clear the
FDB.
Some operating systems do not allow new records to be appended to external files. For
example, you cannot append records to members of partitioned data sets under the z/OS
operating system. If you use this type of operating system, you can append records to
202
Chapter 12
•
Using External Files
files by maintaining blank records in the file, usually at the end of the file. Then, when
you want to add a record, you can update an existing blank record.
After a value is written to the FDB with the FPUT function, the column pointer moves to
the first column following that value.
To return modified records as updates to the file's records, use the FWRITE function to
overwrite each record in the physical file with the contents of the FDB. After the FDB
contents are written to the file, the FDB's column pointer is positioned in column 1, and
the FDB is filled with blanks.
Closing Files in SCL Programs
You should close an external file or directory when your application is finished with it.
To close a file, use the FCLOSE function. To close a directory, use the DCLOSE
function. Ordinarily, when you open a file or directory in the initialization section for the
window, you close it in the window's termination section. When you open a file or
directory in MAIN, you also close it in MAIN.
Changing the Sequence of Reading Records in
SCL Programs
To start reading a file from its beginning, you can move the “read” pointer to the first
record in a file. Then, the next FGET or FPUT function manipulates the first record. To
return the “read” pointer to the file's first record, use the FREWIND function.
In addition to reading records sequentially, you can generally designate records for later
reading, or you can re-read a file's first record. However, some file types do not support
this feature.
When a record is in the FDB, you can mark it so that the “read” pointer can read it later.
For example, because there are no search functions for files, you may want to mark a
found record so you can use it again. To designate a record for later reading, perform
these steps:
1. Use FNOTE to mark the record that is in the FDB for later reading.
2. Use FPOINT to return the “read” pointer to the marked record when you are ready to
read it.
3. Use FREAD to read the record marked by the “read” pointer.
4. After you are finished using the marked record, use DROPNOTE to delete the note
marker and to free the memory that was allocated to store the note.
Other Ways SCL Interacts with External Files
203
Other Ways SCL Interacts with External Files
Introduction
There are other SCL functions that enable you to determine the names and values of
attributes that your operating system maintains for external files. These functions are
listed in the following sections and are described completely in Chapter 13, “SAS
Component Language Dictionary,” on page 209.
Determining Attributes and Attribute Values
Files and directories have several operating system attributes that are assigned and
maintained by the file management system (for example, the date modified and name
attributes). These attributes can vary among operating systems and are described in the
SAS documentation for your operating environment. You can use the following SCL
functions to determine the attributes and attribute values for external files:
Table 12.1
SCL Functions for External File Attributes
FOPTNUM
reports the number of attributes maintained for files in your
operating system.
FOPTNAME
returns the name of a file attribute.
FINFO
returns the value of a file attribute.
Determining Information about an FDB
You can also use SCL functions to find a file's record length and the position of the
column pointer in the FDB.
Table 12.2
SCL Functions for the File Data Buffer
FRLEN
returns the length of a record in the FDB.
FCOL
returns the position of the column pointer in the FDB.
Renaming and Deleting an External File
You can use SCL functions to rename or delete an external file.
Table 12.3
DELETE
SCL Functions for Deleting and Renaming
delete an external file.
204
Chapter 12
•
Using External Files
RENAME
renames an external file.
Reading and Modifying Files in the Same
Directory with SCL
Introduction
To assign a fileref to a directory, use the FILENAME function, just as you would to
assign a fileref to a file. Before you can perform operations on multiple files in a
directory, you must open the directory, just as you open an external file. To open a
directory, use the DOPEN function.
Determining the Number of Files in a Directory
To find out the name of a file in a directory, you must know the number of files in the
directory. You can determine that number by using the DNUM function.
In a program that displays the filenames in an extended table or in an SCL list, you use
the value returned by the DNUM function to determine how many rows to display in the
extended table or list.
Finding the Names of Files
After you find the number of files in the directory, you can use the DREAD function to
read their names.
If you are using DREAD in a program that is not for an extended table, put the function
in a DO loop so that it processes from 1 to the value returned by the DNUM function, as
follows:
dirid=dopen(fileref);
numfiles=dnum(dirid);
do i=1 to numfiles;
name=dread(dirid,i);
...more SCL statements...
end;
Manipulating Files in an Open Directory
When you open and close files in a directory that you opened with the DOPEN function,
you can manipulate any of the files without assigning a fileref to each file. To use this
technique, you must
•
open the file
•
manipulate the file's records
•
close the file.
Reading and Modifying Files in the Same Directory with SCL
205
Opening Files in an Open Directory
To open a file in a directory that you opened with the DOPEN function, use the MOPEN
function. This function returns a file identifier. You can use this identifier with any
function that uses a file identifier value returned by the FOPEN function. That is, you
can use any SCL file function on any file that you have opened with the MOPEN
function. For example, when you open files with the MOPEN function, you use the
FCLOSE function to close the files.
Closing Files in an Open Directory
When your program is finished with a file in an open directory, you must close that file.
To close a file, use the FCLOSE function.
Changing All the Files in a Directory
When you use the directory and file functions, you can create applications that enable
users to make a change in each file in a directory. For example, you might want to
change a date or multiply all the salaries by the same percentage when everyone
represented in the file receives the same percentage raise in pay.
To make the same change to all the files in a directory, first pass the directory name to
the FILENAME function, and then use the DOPEN function to open the directory. Then,
follow these steps:
1. Use the DNUM function to return the number of files in the directory. Use the
number as the end of a DO loop that processes each file.
2. Use the DREAD function to read the name of a file for each repetition of the loop.
3. Use the MOPEN function to open the file.
4. Use the FREAD function to read a record from the file.
5. Use the FPOS function to move the FDB column pointer to the value's start column.
6. Use the FGET function to copy data from the File Data Buffer (FDB) and to assign it
to the specified character variable.
7. Use the FPOS function to return the FDB column pointer to the value's start column.
8. Use the FPUT function to write the modified value back to the FDB.
9. Use the FWRITE function to write the modified record back to the external file.
10. Use the FCLOSE function to close the file at the end of the processing loop.
Creating a Subdirectory
You can use the DCREATE function to create a subdirectory.
Closing a Directory
When your application is finished with the files in a directory, you should close the
directory. To close a directory, use the DCLOSE function.
CAUTION:
206
Chapter 12
•
Using External Files
Be careful to complete operations on all files before closing the directory. When
you use the MOPEN function to open files, be sure your program completes its
operations on all the directory's files before you use the DCLOSE function. When
you use the DCLOSE function, SCL closes all the directory's files that were opened
previously with the MOPEN function.
Other Manipulations for Directories
The following SCL functions provide additional information about directory attributes:
Table 12.4
SCL Functions for Directory Attributes
DOPTNUM
reports the number of directory attributes available for a file.
DOPTNAME
returns the name of a directory attribute for a file.
DINFO
returns the value of a directory attribute for a file.
207
Part 4
Reference
Chapter 13
SAS Component Language Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Chapter 14
The SCL Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 743
Chapter 15
SAS System Return Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
208
209
Chapter 13
SAS Component Language
Dictionary
Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
ACTIVATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
ALARM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
APPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
APPLY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
ARRAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
ASORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
ATTRC and ATTRN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
_BLANK_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
BLOCK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
BUILD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
CATCH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
CATLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
CATNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
CBT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
CENTER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
CEXIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
_CFRAME_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
CLASS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
CLEARLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
CLOSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
CLRFLD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
COLORLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
COMAMID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
COMPAREARRAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
COMPARELIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
CONTENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
CONTINUE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
CONTROL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
COPY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
COPYARRAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
COPYLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
CREATESCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
_CURCOL_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
CURFLD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
CURLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
CUROBS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
_CURROW_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
CURSOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
CURTOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
CURWORD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
210
Chapter 13
•
SAS Component Language Dictionary
DATALISTC and DATALISTN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
DCLOSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
DCREATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
DECLARE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
DELARRAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
DELETE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
DELITEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
DELLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
DELNITEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
DELOBS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
DESCRIBE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
DEVLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
DIALOG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
DINFO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
DIRLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
DISPLAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
DISPLAYED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
DMWINDOW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
DNUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
DO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
DOPEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
DOPTNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
DOPTNUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
DREAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
DROPNOTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
DSID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
DSNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
ENDBLOCK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
ENDCATCH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
ENDCLASS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
ENDLEGEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
ENDMETHOD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
ENDPACKAGE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
ENDSUBMIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
ENDTABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
ENDUSECLASS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
ENTRY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
ENVLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
ERROR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
ERROROFF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
ERRORON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
EVENT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
_EVENT_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
EXECCMD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
EXECCMDI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
EXIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
FAPPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
FCLOSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
FCOL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
FDELETE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
FETCH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
FETCHOBS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
FEXIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
FGET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
FIELD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
FILEDIALOG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
Contents
211
FILEEXIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
FILELIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
FILENAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
FILEREF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386
FILLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
FINFO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
FKEYNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394
FLDATTR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
FLDCOLOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
FNOTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
FONTSEL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
FOPEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
FOPTNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
FOPTNUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
FORMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
FPOINT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
FPOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
FPUT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
_FRAME_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
FREAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
FREWIND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
FRLEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
FSEDIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
FSEP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
FSLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
FSVIEW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
FWRITE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
GETFKEY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
GETFOOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
GETITEMC, GETITEML, GETITEMN, and GETITEMO . . . . . . . . . . . . . . . . . 424
GETLATTR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
GETNITEMC, GETNITEML, GETNITEMN, and GETNITEMO . . . . . . . . . . . . 429
GETPARMID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
GETTITLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
GETVARC and GETVARN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
GETVARF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
GGLOBAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
GGLOBALE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
GGLOBALN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
GOTO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
GRAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
HASATTR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
HOME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
ICCREATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
ICDELETE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
ICDESCRIBE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
ICON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
ICREATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
ICTYPE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453
ICVALUE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
IDELETE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
IMGCTRL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
IMGINIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458
IMGOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460
IMGTERM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
IMPORT (create a table) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463
212
Chapter 13
•
SAS Component Language Dictionary
IMPORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466
INFORMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467
INITROW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468
INPUTC and INPUTN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469
INSERTC, INSERTL, INSERTN, and INSERTO . . . . . . . . . . . . . . . . . . . . . . . . . 471
INSTANCE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
INTERFACE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
IOPTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480
ISACTIVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
ISGRAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482
ISINDEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483
ISSEL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 485
ITEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486
ITEMTYPE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486
IVARLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488
KEYCOUNT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489
LASTCMD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 492
LASTKEY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493
LEAVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494
LEFT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 496
LEGEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497
LENGTH (return string length) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499
LENGTH (declaration) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501
LETTER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
LIBLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504
LIBNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506
LIBREF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508
LISTC and LISTN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
LISTLEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512
LNAMECHK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513
LNAMEGET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514
LNAMEMK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515
LOADCLASS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517
LOADRES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518
LOCATEC and LOCATEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519
LOCK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521
LOOKUPC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522
LVARLEVEL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524
MAKEARRAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 525
MAKELIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527
MAKENLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528
MESSAGEBOX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530
MESSAGEBOXC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531
METHOD (execute) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533
METHOD (define) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535
_METHOD_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543
MLENGTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544
MODIFIED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545
MODVAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546
MOPEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 548
_MSG_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 550
NAMEDITEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551
NAMEDIVIDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554
NAMEITEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555
NAMEMERGE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556
_NEO_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557
Contents
213
NEW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558
_NEW_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 560
NEWVAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
NEXTCMD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564
NEXTWORD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565
NOCHANGE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566
NOTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
NOTIFY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 569
NSELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
NUMFKEYS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
OBSINFO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573
OPEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574
OPENENTRYDIALOG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 576
OPENSASFILEDIALOG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578
OPTGETC and OPTGETN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581
OPTSETC and OPTSETN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 582
PACKAGE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583
PATHNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584
PICCLOSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586
PICDELETE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586
PICFILL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587
PICOPEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589
PMENU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590
POINT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591
POPC, POPL, POPN, and POPO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
POPLEGEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595
POPMENU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596
PREVIEW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 598
PROTECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602
PUSHLEGEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603
PUT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603
PUTC and PUTN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604
PUTLEGEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606
PUTLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607
PUTVARC and PUTVARN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 609
REDIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610
REDIMOPT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 613
REFRESH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615
RENAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615
REPLACE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617
RETURN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 619
REVLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
REWIND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 621
RGBDM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 622
RIGHT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 623
RLINK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 624
ROTLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 625
RSESSION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 627
RSTITLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 627
RUN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 628
SASNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 629
SASTASK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 630
SAVEENTRYDIALOG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 631
SAVELIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633
SAVESASFILEDIALOG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 635
SAVESCREEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638
214
Chapter 13
•
SAS Component Language Dictionary
SCREENNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638
SEARCH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639
SEARCHC, SEARCHL, SEARCHN, and SEARCHO . . . . . . . . . . . . . . . . . . . . . 640
SEARCHPATH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643
SELECT (execute a statement) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
SELECT (a row) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645
SELECTED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647
SELECTICON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 648
_SELF_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 648
SEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649
SET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 651
SETCR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653
SETFKEY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654
SETFLD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655
SETFOOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656
SETITEMC, SETITEML, SETITEMN, and SETITEMO . . . . . . . . . . . . . . . . . . . 657
SETKEY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 659
SETLATTR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662
SETNITEMC, SETNITEML, SETNITEMN, and SETNITEMO . . . . . . . . . . . . . 667
SETPARMID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 670
SETROW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671
SETTITLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 672
SHOWLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673
SORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674
SORTLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
_STATUS_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678
STDMSG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679
STOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680
STRATTR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 681
SUBMIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682
SUBMITCLEAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 685
SUPAPPLY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686
SUPER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 688
SYMGET and SYMGETN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
SYMPUT and SYMPUTN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692
SYSMSG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693
SYSRC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694
SYSTEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 695
THROW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 695
TOPROW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696
TRACEBACK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698
UNGRAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700
UNIQUENUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
UNLOCK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702
UNPROTECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 703
UNSELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704
UPDATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705
USECLASS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706
_VALUE_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711
VARFMT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712
VARINFMT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 713
VARLABEL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 714
VARLEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715
VARLEVEL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716
VARLIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 717
VARNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720
ACTIVATE
215
VARNUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721
VARSTAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 722
VARTYPE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724
WAIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 725
WDEF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726
WHERE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727
WINFO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 730
WNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733
WORD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 734
WORDTYPE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 736
WOUTPUT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 737
WREGION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 739
Dictionary
ACTIVATE
Activates or grays either a Version 6 check box or radio box widget, or a station in a choice group
Category:
Control or Field
Syntax
rc=ACTIVATE(var-name,station<,row> );
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
var-name
is the FRAME entry control or choice group to activate.
Type: Character
station
is the number of the station or item to be activated or grayed:
>0
is the number of the station to be activated.
<0
is the number of the station designated by the absolute value of the
argument to be grayed instead of activated. Users cannot select a station
that has been grayed.
0
indicates that no station is to be activated.
Type: Numeric
216
Chapter 13
•
SAS Component Language Dictionary
Optional Argument
row
is the row number for a choice group that is in the scrollable section of an extended
table. Row is valid for PROGRAM entries but not for FRAME entries. Specify row
only when you want to activate a station from outside an extended table's getrow or
putrow section. Do not specify row if you want to activate a station with the _getrow
or _putrow method or from the getrow or putrow sections.
Type: Numeric
Details
ACTIVATE works only for Version 6 widgets in FRAME entries and for choice groups
in PROGRAM entries. Version 8 and later SCOM controls use attribute settings to
implement this functionality. ACTIVATE is not valid in FSEDIT or FSVIEW programs.
The station value is the number of the check box or the item or button in a check box or
choice group. For example, if your application has three fields named A, B, and C, and
they all belong to the same radio box, then you can make the B field active by passing 2
for the station value (B is the second field).
ACTIVATE makes a check box or an item in a radio box or choice group active by
assigning the station or item number to the associated window variable. ACTIVATE
grays a check box or an item in a radio box or choice group when you assign the
negative number of the station or item. When a window element is grayed, users cannot
select it.
FRAME entry controls can also use the _activate method.
For linked action fields in choice groups, the action-type pair is considered one station.
Linked action fields have the following form:
& &A_____
& &B_____
& &C_____
To make the linked action pair for B active, pass 2 for the value of station, not 4.
Examples
Example 1: Activating a Radio Box Station
Activate the second station in the radio box HOBBY:
rc=activate('hobby',2);
Example 2: Activating a Station in an Extended Table
Make the third station in the fourth row of an extended table the active station in the
choice group LIST:
if (activate('list',3,4)) then
do;
...SCL statements to handle the error condition...
end;
See Also
•
“GRAY” on page 441
•
“ISACTIVE” on page 481
•
“ISGRAY” on page 482
APPEND
•
217
“UNGRAY” on page 700
ALARM
Sounds an alarm on a device when the current window is refreshed or redisplayed.
Category:
Utility
Syntax
ALARM;
Details
The ALARM statement sounds the bell when the current window is refreshed or
redisplayed. This statement works for devices that support sounds.
See Also
•
“CURSOR” on page 296
•
“FIELD” on page 373
APPEND
Appends a new row to a SAS table
Category:
SAS Table
Syntax
sysrc=APPEND(table-id<,option> );
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
an error or warning condition occurred
table-id
contains the identifier for the SAS table, which is returned by the OPEN function.
Type: Numeric
Optional Argument
option
is one of the following options:
218
Chapter 13
•
SAS Component Language Dictionary
'NOSET'
appends a row with all column values set to missing, even if the SET routine has
been called.
'NOINIT'
appends a row with the values currently in the Table Data Vector (TDV), even if
the SET routine has not been called.
Type: Character
Details
APPEND adds a row to the end of a SAS table. By default, the added row contains
missing values. However, you can add a row with the current values in the TDV if SET
has been called or if the NOINIT option is specified as the second argument. If SET has
been called, the NOSET argument can still force APPEND to fill the row with missing
values.
If the SET routine has not been called, you can PUTVARC and PUTVARN to specify
values for each column in the TDV before calling APPEND with the NOINIT option.
You can use INITROW to initialize the TDV to missing to prevent APPEND from
writing bad data to a row values are not explicitly assigned to some columns through
PUTVARC or PUTVARN.
Example: Append a Row
Add a row to the SAS table WORK.DATAONE, which has two columns, FNAME and
SSN. Because SET is called, the values ROBERT and 999-99-9999 are written to the
new row.
tableid=open('work.dataone','u');
call set(tableid);
fname='Fname';
ssn='999-99-9999';
if (append(tableid)) then do;
_msg_=sysmsg();
If SET had not been called, then using the NOINIT option would produce the same
results:
tableid=open('work.dataone','u');
fname='ROBERT';
ssn='999-99-9999';
call putvarc(tableid,varnum(tableid,'fname'),fname);
call putvarc(tableid,varnum(tableid,'ssn'),ssn);
if (append(tableid,'noinit')) then
_msg_=sysmsg();
See Also
•
“OPEN” on page 574
•
“PUTVARC and PUTVARN” on page 609
•
“SET” on page 651
•
“UPDATE” on page 705
•
“INITROW” on page 468
APPLY 219
APPLY
Invokes a method whose arguments are passed from an SCL list
Category:
Object Oriented
Syntax
CALL APPLY(control-id,method-name,arg-list-id);
return-value=APPLY(control-id,method-name, arg-list-id);
Required Arguments
control-id
is the control whose method is being invoked.
Type: Numeric
method-name
is the method to invoke.
Type: Character
arg-list-id
contains the identifier of a list of arguments that the method requires. An invalid arglist-id produces an error condition.
Type: Numeric
return-value
contains the value returned by method-name. The data type for return-value should
match the data type for the called method.
Type: Character, List, Numeric, Object, Class, Interface.
Details
APPLY provides the functionality of CALL SEND except that you can build a dynamic
parameter list at run time instead of coding a fixed parameter list. You can also use
APPLY as a function if the called method returns a value with a RETURN statement in
the program that defines the method.
Comparisons
Instead of using the following statement to invoke a method that you have defined and
named METHOD,
control.method(10,'abc','xyz',x);
you can use
args
args
args
args
args
call
= makelist(4);
= setitemn(args,10,1);
= setitemc(args,'abc',2);
= setitemc(args,'xyz',3);
= setitemn(args,x,4);
apply(control,'method',args);
220
Chapter 13
•
SAS Component Language Dictionary
More useful is the ability to combine APPLY with the ARGLIST= and REST=
keywords in order to write methods that accept variable argument lists:
length _method_ $40;
m: method arglist=args;
call apply(otherControl,_method_, args);
This calls the method with the same arguments to the otherControl.
For example, a control receiving a method could rebroadcast the method to all controls
on its _RECEIVERS_ list:
m: method arglist=args;
_receivers_=getniteml(_self_,'_receivers_',
1, 1, 0);
if _receivers_ then do
r=listlen(_receivers_) to 1 by -1;
call apply(getiteml(_receivers_, r),
_method_, args);
end;
endmethod;
See Also
•
“NOTIFY” on page 569
•
“RETURN” on page 619
•
“SEND” on page 649
•
“SUPAPPLY” on page 686
•
“SUPER” on page 688
ARRAY
Defines elements of an explicit array
Category:
Note:
Declarative Statement
SAS Statement with limitations in SCL
Syntax
ARRAY array-name<{n} > <$> <length> <elements> <(initial-values)> ;
Required Argument
array-name
is the name of the array. It cannot be the same as the name of a window variable.
However, window variables can be elements of an array.
Type: Character
Optional Arguments
{n}
is either the dimension of the array, or an asterisk (*) to indicate that the dimension
is determined from the number of array elements or initial values. Multidimensional
ARRAY
221
arrays are allowed. If an asterisk is specified without any array elements or initial
values, then the array is a reference array. The dimension of this array will be
determined at execution time, based on the corresponding array in the calling
program.
Type: Numeric
$
indicates that the array type is character.
length
is the maximum length of elements in the array. For character arrays, the maximum
length cannot exceed 200. The default length is 8 characters. Length is ignored for
numeric arrays.
Type: Numeric
elements
are the variables (either window or nonwindow variables) that make up the array, or
you can specify '_TEMPORARY_' to create a list of temporary data elements.
Type: Character
initial-values
are the values to use to initialize some or all of the array elements. Separate these
values with commas or blanks. By default, all the elements in an array are initialized
to missing.
Type: Character
Details
Saving Memory
If you have elements that you reference only with subscripting, then you can save
memory by using the _TEMPORARY_ keyword. The SCL compiler has to allocate
memory for the array name and the names of the array elements. However, if this
keyword is used, the compiler allocates memory only for the array name. For large
arrays, this could result in significant memory savings.
Note: Do not use '_TEMPORARY_' for elements if you plan to use the SET routine to
fetch values from a SAS table directly into an array. Use GETVARN and
GETVARC when '_TEMPORARY_' is specified.
Note: You can also declare temporary arrays using the DECLARE statement.
Reference Array
A reference array is a pointer to another defined array. Previously, when an array needed
to be passed as a parameter to a METHOD or ENTRY statement, an array of equal size
needed to be defined in both the calling program and the called program. This technique
used twice as much memory as was actually required. With reference arrays, only one
array needs to be defined with the actual size. The array in the called program uses the
actual memory of the array in the calling program.
By using reference arrays, you can create general array functions, because the array
dimension is determined by the calling program. That is, you do not need to hardcode
the array dimension in the SCL program that contains the ENTRY or METHOD
statement. See the example later in this section for an illustration of this concept.
Using multidimensional reference arrays is allowed when the dimensions match. For
example, if a two-dimensional array is passed in, the reference array must also be twodimensional.
222
Chapter 13
•
SAS Component Language Dictionary
Reference arrays can currently be used as parameters only in a METHOD or ENTRY
statement. Once a reference array has been created by a call to another program, it can
be used in any way that a regular array can be used.
Differences from DATA Step in ARRAY Statement Execution
The ARRAY statement in SCL is very similar to the ARRAY statement in the DATA
step and is used to define single or multidimensional arrays. The ARRAY statement in
SCL differs from the DATA step ARRAY statement in the following ways:
•
SCL does not support implicitly subscripted arrays.
•
SCL does not support the _NUMERIC_, _CHAR_, or _ALL_ keywords.
•
SCL allows a repetition factor for initialization of arrays.
•
SCL allows arrays to be used with the IN operator.
•
SCL supports reference arrays.
•
SCL does not support initialization of over 32,767 values using repetition factors
without using nested groupings. See “Example 3: Using Repetition Factors for Array
Initialization” on page 223.
For details about the ARRAY statement in the Base SAS language, see SAS Statements:
Reference.
Examples
Example 1: Using an Array with the IN Operator
Consider the following code segment:
array a 8 (2 4 6 8 10);
INIT:
b=6;
if b in a then put 'B is in array A';
/* returns location of B in array A */
c=b in a;
put c=;
return;
This code produces the following output:
B is in array A
C=3
Example 2: Using a Reference Array with a METHOD Statement
Assume that an entry SORT.SCL contains the method definition shown below. The
method illustrates the use of a reference array to define a generic sort routine. The
routine is termed generic because NSORT does not need to know the size of the array
that is being passed: the reference array NARRAY takes on the definition of the array
that is specified in the CALL METHOD routine.
nsort: method narray [*]:num;
size = dim( narray );
do i = 1 to size - 1;
do j = i + 1 to size;
if narray( i ) > narray( j ) then
do;
ntemp = narray( i );
ARRAY
223
narray( i ) = narray( j );
narray( j ) = ntemp;
end;
end;
end;
endmethod;
Here is a sample calling program that executes the NSORT method:
array numarray(100);
MAIN:
do i=1 to dim(numarray);
numarray(i)=dim(numarray)-i+1;
end;
call method('sort.scl', 'nsort', numarray);
return;
Example 3: Using Repetition Factors for Array Initialization
In the following statement, note that 1 is repeated three times and the pattern 2,3,4 is
repeated four times:
array A{16}(0,3*1,4*(2,3,4));
This statement initializes the values of the elements of array A as follows:
0, 1, 1, 1, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4
Although SCL does not support initialization of over 32,767 values using regular,
consecutive repetition factors, you can use nested groupings to achieve larger
initializations. The following code demonstrates this repetition factor limitation and how
to work around it.
main:
put "Repetition factor is 32,767. All values assigned.";
array arrayWorks (0:32767) _temporary_ (32767*0);
do a=0 to 32767;
if arrayWorks(a)=0 then zeros+1;
end;
put zeros=;
do i=0 to 3;
put i arrayWorks(i);
end;
zeros=0;
put "Repetition factor is >32,767. Initialization fails.";
array arrayOver(0:32770) _temporary_ (32770*0);
do a=0 to 32770;
if arrayOver(a)=0 then zeros+1;
end;
put zeros=;
do i=0 to 3;
put i arrayOver(i);
224
Chapter 13
•
SAS Component Language Dictionary
end;
zeros=0;
put "Repetition factor is 65,536, but assigned with nested groupings";
put "(256*256 = 65,536). All values assigned.";
array arrayNested (0:65535) _temporary_ (256*(256*0));
do a=0 to 65535;
if arrayNested(a)=0 then zeros+1;
end;
put zeros=;
do i=0 to 3;
put i arrayNested(i);
end;
return;
The output shows how values were assigned.
Repetition factor is 32,767. All values assigned.
zeros=32767
0 0
1 0
2 0
3 0
Repetition factor is >32,767. Initialization fails.
zeros=1
0 0
1 .
2 .
3 .
Repetition factor is 65,536, but assigned with nested groupings
(256*256 = 65,536). All values assigned.
zeros=65536
0 0
1 0
2 0
3 0
See Also
“DECLARE” on page 304
ASORT
Sorts an array
Category:
Array
Syntax
rc=ASORT(array<,order> <,elements> );
ASORT
225
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
array
is an SCL array that was declared in an ARRAY statement.
Type: Character
Optional Arguments
order
specifies the order for the sort:
'A'
ascending order (the default)
'D'
descending order
Type: Character
elements
is the number of elements to sort.
Type: Numeric
Details
By default, the array is sorted in ascending order. You can use the optional order
argument to specify either ascending or descending order.
By default, the entire array is sorted. You can use the optional elements argument to
restrict sorting to the specified number of elements (starting from the beginning of the
array).
If the value of the elements argument is greater than the total number of array elements,
the program halts execution and sends an error message to the log.
Example: Sort Part of an Array
Sort the first five items of array VALUES in ascending order:
array values[8] val1-val8 (3,5,2,1,6,8,7,4);
if (asort(values,'d',5)) then _msg_=sysmsg();
else do;
_msg_='Sort was successful';
do i=1 to dim(values);
put values{i}=;
end;
end;
This produces the following output:
values[ 1 ]=6
values[ 2 ]=5
226
Chapter 13
•
SAS Component Language Dictionary
values[
values[
values[
values[
values[
values[
3
4
5
6
7
8
]=3
]=2
]=1
]=8
]=7
]=4
ATTRC and ATTRN
Return the value of an attribute for a SAS table
Category:
SAS Table
Syntax
attr-value=ATTRC(table-id,attr-name);
attr-value=ATTRN(table-id,attr-name);
Required Arguments
attr-value
contains the value of the SAS table attribute. For ATTRC, the value is for a character
attribute. For ATTRN, the value is for a numeric attribute.
Type: Character, Numeric
table-id
contains the identifier for the SAS table. This is the identifier that was returned by
the OPEN function when the table was opened. If table-id is invalid, the program
halts.
Type: Numeric
attr-name
is the name of the SAS table attribute. If attr-name is invalid, then a missing or null
value is returned for attr-value.
Type: Character
Details
Attributes for the ATTRC Function
To check for a character attribute of a SAS table, use ATTRC with one of the following
values for attr-name:
'CHARSET'
returns a string indicating the character set of the machine that created the SAS table.
It returns either one of the following values, or an empty string if the SAS table is
not sorted:
ASCII
ASCII character set
EBCDIC
EBCDIC character set
ATTRC and ATTRN
227
HASCII
extended ASCII character set
ANSI
OS/2 ANSI standard ASCII character set
OEM
OS/2 OEM code format
'DATAREP'
returns a string indicating the type of file:
NATIVE
local files.
FOREIGN
non-native files.
'ENCRYPT'
returns 'YES' or 'NO' depending on whether the SAS table is encrypted.
'ENGINE'
returns the name of the engine used to access the SAS table.
'LABEL'
returns the label assigned to the SAS table.
'LIB'
returns the libref of the SAS data library in which the SAS table resides.
'MEM'
returns the name of the SAS data library member.
'MODE'
returns the mode in which the SAS table was opened, such as:
I
INPUT mode, allows random access if the engine supports it; otherwise, defaults
to IN mode
IN
INPUT mode, reads sequentially and allows revisiting rows
IS
INPUT mode, reads sequentially but does not allow revisiting rows
N
NEW mode (to create a new SAS table)
U
UPDATE mode, allows random access if the engine supports it; otherwise,
defaults to UN mode
UN
UPDATE mode, reads sequentially and allows revisiting rows
US
UPDATE mode, reads sequentially but does not allow revisiting rows
V
UTILITY mode, allows modification of column attributes and indexes that are
associated with the SAS table.
For more information about open modes, see “OPEN” on page 574.
228
Chapter 13
•
SAS Component Language Dictionary
'MTYPE'
returns the type of the SAS data library member.
'SORTEDBY'
returns an empty string if the SAS table is not sorted. Otherwise, returns the names
of the BY columns in the standard BY statement format.
'SORTLVL'
returns an empty string if the SAS table is not sorted. Otherwise, returns one of the
following:
WEAK
The sort order of the SAS table is not validated. That is, the sort order was
established by a user (for example, through a SORTEDBY SAS data set option).
The system cannot validate its correctness, so the order of the rows cannot be
depended upon.
STRONG
The sort order of the SAS table is validated. That is, the order of its rows can be
depended upon. The sort order was established by the software (for example,
through PROC SORT or through the OUT= option on the CONTENTS
procedure).
'SORTSEQ'
returns an empty string if the SAS table is sorted on the native machine or if the sort
collating sequence is the default for the operating system. Otherwise, returns the
name of the alternate collating sequence that is used to sort the file.
'TYPE'
is the SAS table type.
Attributes for the ATTRN Function
To check for a numeric attribute, use ATTRN with one of the following values for attrname:
'ANY'
specifies whether the table has rows or columns:
-1
The table has no rows or columns.
0
The table has no rows.
1
The table has both rows and columns.
'ALTERPW'
indicates whether a password is required in order to alter the SAS table:
1
The SAS table is alter protected.
0
The SAS table is not alter protected.
'ANOBS'
indicates whether the engine knows the number of rows:
1
The engine knows the correct number of rows.
ATTRC and ATTRN
229
0
The engine does not know the correct number of rows.
'ARAND'
indicates whether the engine supports random access:
1
The engine supports random access.
0
The engine does not support random access.
'ARWU'
indicates whether the engine can manipulate files:
1
The engine is not read-only. It can create or update SAS files.
0
The engine is read-only.
'AUDIT'
indicates whether an audit trail is active:
1
An audit trail is active.
0
No audit trail is active.
'AUDIT_BEFORE'
indicates whether the audit trail will log an image of the row before updates:
1
The audit trail will log an image of the row before updates.
0
No image of the row will be logged before updates.
'AUDIT_DATA'
indicates whether the audit trail will log an image of the row after updates:
1
The audit trail will log an image of the row after updates.
0
No image of the row will be logged after updates.
'AUDIT_ERROR'
indicates whether the audit trail will log an image of an unsuccessful update to the
row:
1
The audit trail will log an image of an unsuccessful update to the row.
0
No image of an unsuccessful update to the row will be logged.
'CRDTE'
returns the SAS table creation date. The value returned is the internal SAS
DATETIME value for the creation date. Use the DATETIME format to display this
value.
230
Chapter 13
•
SAS Component Language Dictionary
'GENMAX'
returns the maximum number of generations.
'GENNEXT'
returns the next generation number to generate.
'ICONST'
returns information on the existence of integrity constraints for a SAS table:
0
No integrity constraints.
1
One or more general integrity constraints.
2
One or more referential integrity constraints.
3
Both one or more general integrity constraints and one or more referential
integrity constraints.
'INDEX'
indicates whether the SAS table supports indexing:
1
Indexing is supported.
0
Indexing is not supported.
'ISINDEX'
indicates whether the SAS table is indexed:
1
At least one index exists for the SAS table.
0
The SAS table is not indexed.
'ISSUBSET'
indicates whether the SAS table is a subset:
1
At least one WHERE clause is active.
0
No WHERE clause is active.
'LRECL'
returns the logical record length.
'LRID'
returns the length of the record ID.
'MODTE'
returns the last date and time the SAS table was modified. Use the DATETIME
format to display this value.
'NDEL'
returns the number of deleted rows in the SAS table.
ATTRC and ATTRN
231
'NLOBS'
returns the number of logical rows (those not marked for deletion). An active
WHERE clause does not affect this number.
'NLOBSF'
returns the number of logical rows (those not marked for deletion) that match the
active WHERE clause.
Note: NLOBSF should be used with caution. Passing NLOBSF to ATTRN requires
the engine to read every row from the table that matches the WHERE clause.
Based on the file type and size, this can be a time-consuming process.
'NOBS'
returns the number of physical rows (including those marked for deletion). An active
WHERE clause does not affect this number.
'NVARS'
returns the number of columns in the SAS table.
'PW'
indicates whether a password is required in order to access the SAS table:
1
The SAS table is protected.
0
The SAS table is not protected.
'RADIX'
indicates whether access by row number is allowed:
1
Access by row number is allowed.
0
Access by row number is not allowed.
Note: A SAS table on a tape engine is index addressable even though it cannot be
accessed by row number.
'READPW'
indicates whether a password is required in order to read the SAS table:
1
The SAS table is read protected.
0
The SAS table is not read protected.
'TAPE'
indicates whether the SAS table is a sequential tape file:
1
The SAS table is a sequential tape file.
0
The SAS table is not a sequential tape file.
'WHSTMT'
returns information about active WHERE clauses:
0
No WHERE clause is active.
232
Chapter 13
•
SAS Component Language Dictionary
1
A permanent WHERE clause is active.
2
A temporary WHERE clause is active.
3
Both permanent and temporary WHERE clauses are active.
'WRITEPW'
indicates whether a password is required in order to write to the SAS table:
1
The SAS table is write protected.
0
The SAS table is not write protected.
Examples
Example 1: Using the ATTRC Function and MODE
Ensure that the SAS table has been opened in UPDATE mode and display an error
message if it is not open:
mode=attrc(tableid,'MODE');
if (mode ne 'U') then _msg_=
'Table not open in UPDATE mode.';
else rc=sort(tableid,'name');
Example 2: Using the ATTRN Function and WHSTMT
Determine whether a WHERE clause is currently active for a SAS table:
iswhere=attrn(tableid,'whstmt');
if (iswhere) then _msg_=
'A WHERE clause is currently active.';
Example 3: Using the ATTRN Function to Determine Audit Trail
Information
To test the AUDIT attributes of the ATTRN function, follow these steps:
1. Create a data set with an audit file by entering the following code in the SAS Editor
and then submitting it:
data sasuser.class;
set sashelp.class;
run;
proc datasets lib=sasuser;
audit class;
initiate;
log data_image=yes error_image=no before_image=yes;
run;quit;
2. Query the audit file by entering the following code in an SCL file:
INIT:
dsid=open('sasuser.class');
auditIsActive=attrn(dsid,'AUDIT');
auditHasDataImage=attrn(dsid,'AUDIT_DATA');
BLOCK
233
auditHasErrorImage=attrn(dsid,'AUDIT_ERROR');
auditHasBeforeImage=attrn(dsid,'AUDIT_BEFORE');
put auditIsActive= auditHasDataImage= auditHasErrorImage= auditHasBeforeImage=;
return;
3. When you compile and then execute the SCL code, the SAS log displays:
auditIsActive=1 auditHasDataImage=1 auditHasErrorImage=0 auditHasBeforeImage=1;
See Also
•
“DESCRIBE” on page 316
•
“OPEN” on page 574
_BLANK_
Special missing value
Category:
System Variable
Details
_BLANK_ is a system variable that is created for every SCL program that you compile.
The compiler creates a space for _BLANK_ in the SCL data vector. In SAS/AF
applications, you can compare the value of window variables against the value
_BLANK_ to test whether a value has been entered in a field in the window. The test is
valid for both numeric and character variables. You can also use _BLANK_ in
assignment statements to reset a window variable to a blank, as if the user had not
entered a value in the field. You cannot reset the value of the _BLANK_ variable itself.
In comparison operations, _BLANK_ is considered the smallest missing value.
Example
The following code fragment prints a message if X is modified and is blank:
if modified(x) and x eq _blank_ then
_msg_ = 'Please enter a value';
See Also
•
“CLRFLD” on page 264
•
“SETFLD” on page 655
BLOCK
Displays a menu containing up to 12 choice blocks and returns the number of the user's choice
Category:
Window
234
Chapter 13
•
SAS Component Language Dictionary
Syntax
choice=BLOCK(window-name,title,color,text-1, . . . ,text-12<,icon-1, . . . ,icon-12> );
Required Arguments
choice
returns either the number (1-12) of the selected block, or one of the following:
−99
if a user requested help for SAS software
−1 to −12
if a user requested help for the block
0
if a user issued the END, CANCEL, or BYE command
99
if an unknown command is issued (see “WORD” on page 734 ).
Type: Numeric
window-name
is the title (up to 80 characters) for the window.
Type: Character
title
is the title (up to 60 characters) for the menu's title box.
Type: Character
color
is a number from 0 to 33 that represents the combination of colors to be used for the
blocks. The colors and numbers are listed in Table 13.1 on page 235. Some devices
do not support changing the background color. If you have specified that icons be
used with BLOCK, then the specified color combination may not take effect. The
display of icons is host specific, and therefore the color may be controlled by the
host operating system. (Under Windows or OS/2, use the Color Palette to alter icon
colors. Under X windows, set X resources to control icon colors.)
Type: Numeric
text-1, . . . , text-12
is the text for each block or icon to display (up to 14 characters). The blocks or icons
are displayed in groups of four. Blocks for the first four text values are displayed on
the first row, blocks for the second four text values are displayed on the middle row,
and blocks for the last four text values are displayed on the last row. Twelve values
are required, but you can use null values for block positions that you do not want
displayed.
Type: Character
Optional Argument
icon-1, . . . , icon-12
are numbers for icons to display in place of the blocks. If no values are provided for
icons, or if the host system does not support icons, then standard rectangular blocks
are displayed. If you specify a number for which no icon is defined, then the default
SAS icon is displayed. If at least one icon number is specified, and the total number
of icons is less than the total number of text labels, then the default SAS icon is
displayed for text labels that lack an associated icon number.
BLOCK
235
Type: Numeric
Details
The number of text values that you specify determines how many blocks of icons are
displayed in the menu. In order to display an icon menu, you must specify at least one
icon position, although you can display the default SAS icon by specifying 0 for
positions for which a value for text is supplied.
Because BLOCK does not generate a physical display window, window options such as
KEYS are not recognized. The BLOCK function windows recognize only DMKEYS
settings. To alter DMKEYS settings for a BLOCK menu, you can use GETFKEY and
SETFKEY in a program that runs before the BLOCK menu opens. This program must
have a display screen associated with it.
This function attempts to display the blocks in the best manner depending upon the
characteristics of the user's display device. The function displays up to three rows of four
blocks. Blocks are displayed in the order in which the text arguments appear in the
function. Only the nonblank choices are displayed, and the blocks in each row are
centered in the row.
When the function is called, it queries the current value of choice. If the value of choice
corresponds to a valid selection number, the cursor is positioned on the correct block.
Otherwise, the cursor is positioned in the upper-left corner of the window.
To make a selection from the block menu, a user must move the cursor to the appropriate
block and then press ENTER or click the mouse. BLOCK returns the index of the
selection.
If a user presses the HELP key on one of the selections, then the negative of the
selection is returned. If a user presses the HELP key while the cursor is not on one of the
blocks, then the value −99 is returned.
If a user issues the END or CANCEL command via a function key, then the value 0 is
returned.
Use ENDBLOCK to close the menu window that is opened by BLOCK.
Table 13.1
Values for the Color Argument
Color
Background
Border
Text
Icon
Shadow
0
black
white
white
white
white
1
black
gray
cyan
gray
blue
2
black
gray
cyan
gray
blue
3
black
cyan
cyan
gray
cyan
4
black
gray
white
cyan
gray
5
black
cyan
yellow
cyan
blue
6
black
gray
white
blue
gray
7
black
gray
yellow
blue
gray
8
black
gray
white
red
gray
236
Chapter 13
•
SAS Component Language Dictionary
Color
Background
Border
Text
Icon
Shadow
9
black
gray
white
pink
gray
10
black
gray
white
yellow
gray
11
black
gray
white
red
blue
12
blue
gray
cyan
gray
black
13
blue
gray
yellow
gray
black
14
blue
gray
white
gray
black
15
blue
gray
white
magenta
black
16
blue
gray
white
red
black
17
blue
gray
white
cyan
black
18
blue
yellow
white
yellow
black
19
blue
gray
white
magenta
gray
20
blue
gray
white
red
gray
21
gray
blue
black
blue
black
22
gray
red
black
red
black
23
gray
magenta
black
magenta
black
24
gray
blue
black
cyan
blue
25
gray
cyan
black
cyan
black
26
red
gray
white
gray
black
27
red
gray
black
gray
black
28
pink
gray
white
gray
black
29
pink
gray
black
gray
black
30
yellow
gray
black
gray
black
31
brown
gray
gray
gray
black
32
background*
border*
foreground*
secondary
black
background*
33
secondary
secondary
background*
border*
* SASCOLOR window element names.
foreground*
background*
black
BUILD
237
Example: Create a Menu
Create a menu with five choices represented by icons. The first row contains two icons,
Outline and Index. The second row contains two icons, Compare Files and
Calendar. The third row contains a single icon, End.
Because the CHOICE variable is assigned the value 5 before BLOCK is called, the
cursor is positioned on the Compare Files icon when the window opens. When a user
makes a selection, the SELECT statement either exits the DO loop or calls another
PROGRAM entry. When control returns from the called program, the menu is displayed
again.
INIT:
choice=5;
LOOP:
do while(choice ne 0);
choice=block('Writers Toolbox',
'Main Menu',6,'Outline','Index',
'','','Compare Files',
'Calendar','','',
'End','','','',
1,2,0,0,3,4,0,0,111,0,0,0);
select(choice);
when(1) call display('outl.scl');
when(2) call display('index.scl');
when(5) call display('compare.scl');
when(6) call display('calend.scl');
when(9) leave LOOP;
otherwise do;
if (choice<0) then
call display('help.scl',choice);
end;
end;
end;
call endblock();
return;
See Also
“ENDBLOCK” on page 341
BUILD
Invokes the BUILD window in SAS/AF software
Category:
Utility
Syntax
CALL BUILD(entry<,open-mode<,resource> <,pmenu> > );
238
Chapter 13
•
SAS Component Language Dictionary
Required Argument
entry
is the name of an entry in a SAS catalog. A one-level name is assumed to be
WORK.catalog. A two-level name is assumed to be libref.catalog. A three-level
name is assumed to be libref.catalog.entry.PROGRAM. A four-level name is
assumed to be libref.catalog.entry.type.
If a catalog is specified instead of a catalog entry, the Explorer window is brought up
and the three optional parameters are ignored.
Type: Character
Optional Arguments
open-mode
is the mode in which to open the catalog:
'EDIT'|'E'
opens the catalog entry for editing. (This is the default.)
'BROWSE'|'B'
opens the catalog entry for browsing.
'COMPILE <NOMSG>'|'C <NOMSG>'
compiles the FRAME, PROGRAM, or SCL entry specified in entry. The NOMSG
option prevents NOTE messages from being sent to the SAS log when batch files
are being run (or to the LOG window for all other files) when the program is
compiled, but it does not suppress compiler error or warning messages.
Type: Character
resource
is the RESOURCE entry if entry is a FRAME entry. A one- or three-level name can
be specified. A one-level name assumes that the RESOURCE entry is in the current
catalog, the SASUSER.PROFILE catalog, or the SASHELP.FSP catalog.
Type: Character
pmenu
is the PMENU entry for the DISPLAY window. If pmenu is not supplied, a default
PMENU entry is displayed. A one-level name assumes that the PMENU entry is in
either the current catalog, the SASUSER.PROFILE catalog, or the SASHELP.FSP
catalog. For FRAME and PROGRAM entries, you can specify a secondary PMENU
entry for the SOURCE window. Use a space to separate a secondary PMENU name
from a main PMENU name.
Type: Character
Details
You can use the BUILD routine to
•
open catalog entries from within an application
•
compile PROGRAM, FRAME, or SCL entries without displaying the contents of the
entries
•
view SAS/GRAPH or SAS/AF entries.
If a catalog entry is specified in the first parameter instead of an entry, none of the
optional parameters are honored.
CATCH
239
Note: When a program uses the BUILD routine, SAS/AF software must be licensed at
sites where the application is executed.
Examples
Example 1: Opening an Entry
Open a PROGRAM entry named NAME in edit mode in the catalog MYLIB.MYCAT:
call build('mylib.mycat.name');
Example 2: Compiling a FRAME Entry
Compile the source code for the entry A.FRAME in the WORK.TEST catalog without
opening a DISPLAY window for the entry and without displaying any NOTES:
call build('work.test.a.frame','compile nomsg');
Example 3: Specifying RESOURCE and PMENU Entries
Edit a FRAME using a particular RESOURCE and PMENU:
call build('lib.cat.name.frame','e',
'lib.cat.build.resource','lib.cat.build.pmenu');
Example 4: Specifying a Secondary PMENU Entry
Edit a FRAME entry using a custom PMENU for both the DISPLAY and SOURCE
windows. The DISPLAY window uses MYPMENU1.PMENU, and the SOURCE
window uses MYPMENU2.PMENU.
call build('lib.cat.a.frame','e','',
'mypmenu1 mypmenu2');
See Also
•
“CBT” on page 245
•
“DISPLAY” on page 326
CATCH
Processes an exception that has been thrown with the THROW statement
Category:
Control Flow
Syntax
CATCH exception;
/* SCL statements to process the exception */
ENDCATCH;
Required Argument
exception
is the local variable for the exception (which is an instance of the SCL Exception
class) that you want to process.
240
Chapter 13
•
SAS Component Language Dictionary
Details
CATCH blocks must always be enclosed in DO statements.
When an exception is raised via the THROW statement, normal execution of the
program stops, and SCL begins looking for a CATCH block to process the exception.
The CATCH block can contain any statements needed to process the exception,
including additional CATCH and THROW statements.
SCL uses the scope of the DO group that contains the CATCH block and the class of the
exception to determine which CATCH block to execute. For details, see “How SCL
Determines Which CATCH Block To Execute” on page 175.
Each entry in the stack can process an exception and then pass it back up the stack by
rethrowing it, which allows the calling entry to perform additional processing. Each
entry can perform whatever processing is relevant to that entry.
If an exception is rethrown within a CATCH block, no other CATCH block within the
same scope can recatch the exception. The exception is passed out of the scope where it
was thrown. Also, you cannot define multiple CATCH blocks for the same exception
within the same scope.
Example: Catching an Exception
The following DO group declares a local exception variable called NE, creates a new
instance of NE, and throws the new exception. The CATCH block prints the traceback
information that is automatically stored by SCL when an exception is thrown.
do;
dcl SCLException NE = _new_ NewException('Exception in method m');
throw NE;
catch NE;
put NE.getMessage();
/* Print exception information. */
call putlist(NE.traceback);
endcatch;
end;
See Also
•
“THROW” on page 695
•
“Introduction to SCL Exception Handling” on page 171
CATLIST
Displays a host selector window that lists entries in a SAS catalog, and returns user selections
Category:
Catalog, Selection List
Syntax
selections=CATLIST(catalog-name,type,num-sel, prefix<,message> );
CATLIST 241
Required Arguments
selections
contains one or more user selections from the list. Separate multiple selections with
one or more blanks. By default, selections is 200 bytes long. To accommodate values
longer than 200 bytes, explicitly declare selections with a longer length.
Type: Character
catalog-name
is either a SAS catalog name, in the form libref.catalog, or * to allow a user to
interactively select a libref, catalog, and entry.
Type: Character
type
is the entry type to list for selection (for example, SCL or FRAME). To display the
names of all entries in the catalog, use 'ALL' or ' '.
num-sel
is the maximum number of items a user can select. To display the list for information
only (no selections allowed), specify 0. To specify an unlimited number of
selections, use a value that is equal to or larger than the number of available
selections. A user cannot make a number of selections that exceeds the number of
items in the list.
Type: Numeric
prefix
specifies whether selected entries are prefixed by the catalog name:
'Y'
returns selected names in the form libref.catalog.entry.type. This is the
default value if catalog-name is *.
'N' | ' '
returns selected names in the form entry.type.
Type: Character
Optional Arguments
message
is the text for the message that is displayed at the top of the selection list window.
The default message tells users to make up to num-sel selections.
Type: Character
autoclose
is an obsolete argument but is retained for compatibility with earlier releases. If you
want to specify a value for num-sel, then specify ' ' as a placeholder for this
argument.
Type: Character
Details
You can provide default values that will be initially selected when the catalog selection
list is displayed. To do this, assign the values to the selections variable before calling
CATLIST. If selections contains valid values when the function is invoked, then those
names are automatically designated as selected when the selection list is displayed.
242
Chapter 13
•
SAS Component Language Dictionary
If a user closes the Catalog Entry Selector window without making a selection, then
CATLIST returns a blank value unless there was an initial value for the selections
variable before CATLIST was called.
Selections from the window can be returned in the current result list, if one is available.
The current result list is a special SCL list that is automatically filled with the values that
have been selected from a selection list. To create a current result list, use the
MAKELIST function to create it, and use the CURLIST function to designate it as the
current result list. The current result list must exist before you call the CATLIST
function.
When CATLIST is invoked, the current result list is cleared. After CATLIST is invoked,
the result list contains the following named items:
TAG
identifies the list as one that was created by CATLIST.
Type: Character
COUNT
contains either the number of selected elements, or 0 if a user makes no selections or
issues a CANCEL command in the list window.
Type: Numeric
NAME
contains the uppercase name of each selected catalog entry. If the value of prefix is
Y, then the prefix is appended to the beginning of each name. There is one NAME
element for each selection.
Type: Character
DESC
contains the description of each selected catalog entry. There is one DESC element
for each selection. The value of DESC is in the same case that was entered
originally.
Type: Character
DATE
contains the date of last modification for each selected catalog entry. There is one
DATE element for each selected catalog entry.
Type: Character
Because some engines support mixed-case filenames, CATLIST now retains the cases of
the returned selected items. This may cause your application to fail if your application
contains code that assumes the returned selection is uppercased. For example,
if (catlist(dsid, 'TESTNDX')='NDXVAR')
must be changed to
if (upcase(catlist(dsid, 'TESTNDX'))='NDXVAR'
If the application cannot be modified, you may need to specify the
VALIDVARNAME=V6 system option when you run the application to ensure that the
selections returned from the CATLIST function will be uppercased.
Example
Display a selection list that contains the entries in the catalog MYLIB.TEST, and allow
users to make up to five selections. Use GETNITEMC to retrieve the selected values
from the current result list.
CATNAME
listid=makelist();
rc=curlist(listid);
selections=catlist('mylib.test','all',5);
n=getnitemn(listid,'COUNT');
do i=1 to n;
name=getnitemc(listid,'NAME',i);
desc=getnitemc(listid,'DESC',i);
date=getnitemc(listid,'DATE',i);
put name= desc= date=;
end;
See Also
•
“CURLIST” on page 293
•
“DIRLIST” on page 323
•
“FILELIST” on page 381
•
“LIBLIST” on page 504
CATNAME
Defines a concatenated catalog, which contains a logical combination of the entries in two or more
catalogs
Category:
Catalog
Syntax
rc=CATNAME(cat-name,action<,catalog-list><,list-id>);
Required Arguments
rc
contains the return code for the operation:
0
successful
1
not successful
Type: Numeric
cat-name
is a two-level name (libref.catalog) for the concatenated catalog. The libref must
already be defined.
Type: Character
action
specifies the action to take on cat-name:
'SET'
sets the definition.
'CLEAR'
clears the definition.
'LIST'
lists the members and saves them in the SCL list referenced by listid.
243
244
Chapter 13
•
SAS Component Language Dictionary
Type: Character
Optional Arguments
catalog-list
lists the two-level names (libref.catalog) of two or more SAS catalogs whose entries
are logically combined in cat-name. Use at least one blank space to separate catalog
names. This list can contain concatenated catalogs that were previously defined with
the CATNAME function.
Type: Character
list-id
contains the identifier for the list of catalogs to be logically combined in cat-name, if
action is SET and catalog-list is not specified. If action is LIST, then the list
contains the following information about all of the entries:
CATNAME
The catalog name, which is a two-level name (libref.catalog) for the concatenated
catalog.
Type: Character
LEVELS
The total number of levels of the defined catalog name.
Type: Numeric
(sublist1...sublistn)
Sublist number 1 to n, where n is the total number of levels.
Type: List
The sublist elements are as follows:
•
LEVEL, which is the level number. Type: Numeric
•
CATALOG, which is the catalog name. Type: Character
•
ENGINE, which is the engine name. Type: Character
•
PHYSICAL NAME OF LIBRARY, which is the physical name of the library.
Type: Character
Type: Numeric or List
Details
CATNAME defines a concatenated catalog that is a logical combination of the entries in
two or more SAS catalogs. When the program uses cat-name as the catalog in a catalog
entry name, SAS searches for the specified entry in the catalogs specified in catalog-list
or list-id. A concatenated catalog name that is defined with CATNAME can be part of
catalog-list or list-id for another CATNAME function.
This feature is most useful for debugging and testing during application development. It
eliminates the need to copy a whole catalog when you need to test and change a single
catalog entry that contains a particular method.
CBT
245
Examples
Example 1: Defining a CATNAME
Create concatenated catalog S.T, which logically combines the entries in catalogs A.B
and C.D. Then, create concatenated catalog E.F, which contains the logical combination
of the entries in the concatenated catalog S.T as well as the entries in Q.T and X.Y. A
subsequent reference in a program to S.T.TEST.SCL causes SAS to search for
A.B.TEST.SCL and then for C.D.TEST.SCL. A reference to E.F.TEST.SCL causes SCL
to search for A.B.TEST.SCL, then for C.D.TEST.SCL, then for Q.T.TEST.SCL, and
finally for X.Y.TEST.SCL.
rc=catname ('s.t','set','a.b c.d');
rc=catname ('e.f','set','s.t q.t x.y');
Example 2: Defining a CATNAME for a list-id
Use the 'LIST' action to query the definition of E.F from Example 1.
list=makelist();
rc=catname('e.f','list',”,list);
call putlist(list);
See Also
“SEARCH” on page 639
CBT
Runs a CBT entry
Category:
Modular Programming and Object Oriented
Syntax
CALL CBT(entry<,frame><,frame-name>);
Required Argument
entry
is the name of a CBT entry. Specify a CBT entry in the current catalog with entry.
Specify an entry in the current catalog with entry.type. Specify a CBT entry in a
different catalog with libref.catalog.entry. Specify a different type of entry in a
different catalog with libref.cat-name.entry.type.
Optional Arguments
frame
is the number of the frame in the CBT entry to be displayed initially.
Type: Numeric
frame-name
is the name assigned to the frame in the CBT to be displayed initially. If this
argument is specified, the value of frame is ignored.
Type: Character
246
Chapter 13
•
SAS Component Language Dictionary
Details
The CBT routine opens a CBT entry window. You can optionally specify the name or
number of the CBT frame to display initially. For information about CBT entries, see the
SAS documentation for SAS/AF software. You can use CBT entries to link detailed
instructional information with an application so that the information is readily available.
The following restrictions apply for users of a CBT entry that is called from an SCL
program:
•
The SAVE command is not recognized.
•
=X returns the user to the calling program.
•
QCANCEL returns the user to the calling program.
•
QEND returns the user to the calling program.
Examples
Example 1: Displaying a Particular CBT Frame
Display the second frame of the entry EXAMPLE.CBT:
call cbt('example',2);
Display the frame named ABC of the entry EXAMPLE.CBT:
call cbt('example',1,'abc');
Example 2: Calling a CBT Entry
Suppose an application requires users to be familiar with a particular set of terminology.
You use the following program to call a CBT course (in this example,
TERMINAL.CBT) that teaches the appropriate information. The following example runs
the CBT entry if a user issues the command TEACH. Then, when the user exits the CBT
course, it returns control to the SCL statement that follows the call to TERMINAL.CBT.
control always;
if (upcase(word(1))='TEACH') then
do;
call nextcmd();
call cbt('terminal');
end;
See Also
•
“DISPLAY” on page 326
•
“GOTO” on page 439
CENTER
Returns a centered character string
Category:
Character
CEXIST
247
Syntax
centered-string=CENTER(string<,length>);
Required Arguments
centered-string
contains the centered character string. If centered-string already exists, then
specifying length changes the length of centered-string to the number of characters
specified in length.
Type: Character
string
contains the character string to be centered.
Type: Character
Optional Argument
length
contains the length in which the character string is to be centered. The default is the
maximum length of centered-string.
Type: Numeric
Details
The default length is the maximum length of centered-string. The string is centered by
padding with spaces. To enable CENTER to work properly when centered-string is a
window variable, set the justification attribute (JUST) for the control or field to NONE.
To left- or right-justify a string, use LEFT or RIGHT, respectively.
See Also
•
“LEFT” on page 496
•
“RIGHT” on page 623
CEXIST
Verifies the physical existence of a SAS catalog or SAS catalog entry
Category:
Catalog
Syntax
rc=CEXIST(entry< ,'U'>);
Required Arguments
rc
contains the return code for the operation:
1
The SAS catalog or catalog entry exists.
0
The SAS catalog or catalog entry does not exist.
248
Chapter 13
•
SAS Component Language Dictionary
Type: Numeric
entry
is SAS catalog, or the name of an entry in a catalog. A one- or two-level name is
assumed to be the name of a catalog. To test for the existence of an entry within a
catalog, use a three- or four-level name.
Type
Character
Note
The CEXIST function verifies whether the entry physically exists.
Concatenated names are a logical concatenation, not a physical entity. If you
specify a concatenated name for entry, CEXIST will return a 0.
Optional Argument
'U'
tests whether the catalog specified in entry can be opened for updating.
Type: Character
Examples
Example 1: Testing Whether a Catalog Can Be Updated
Test whether the catalog LIB.CAT1 exists and can be opened for update. If the catalog
does not exist, a message is displayed on the message line.
if (cexist('lib.cat1','u')) then
_msg_='The catalog LIB.CAT1 exists and can be
opened for update.';
else _msg_=sysmsg();
Example 2: Verifying the Existence of a Catalog
Verify the existence of the entry X.PROGRAM in LIB.CAT1:
if (cexist('lib.cat1.x.program')) then
_msg_='Entry X.PROGRAM exists';
else _msg_=sysmsg();
See Also
“EXIST” on page 361
_CFRAME_
Contains the identifier of the FRAME entry that is currently executing
Category:
System Variable
Details
_CFRAME_ is a system variable that is provided automatically for FRAME entries.
_CFRAME_ has a valid value only when a FRAME entry's SCL code is running or
when a FRAME entry or component method is running.
CLASS 249
Example
Suppose the entry FIRST.FRAME contains an icon. The icon's _select method is defined
to run SECOND.FRAME, which contains the following program:
INIT:
/* Send a method to the current FRAME */
_CFRAME_._setMsg('Running the Select method');
return;
TERM:
/* Send a method to the FRAME that */
/* contains the icon
*/
_FRAME_._setMsg('The Select method has finished.');
return;
When FIRST.FRAME displays and a user selects the icon, SECOND.FRAME displays
with the message “Running the Select method.” After the user ends from
SECOND.FRAME, FIRST.FRAME displays the message “The Select method has
finished.” This is accomplished by sending the _setMsg method to _CFRAME_ (the
FRAME entry that is currently running) in the INIT section and by sending _setMsg to
_FRAME_ (the FRAME entry that contains the icon) in the TERM section.
See Also
“_FRAME_” on page 410
CLASS
Creates a class using SCL code
Category:
Object Oriented
Syntax
< ABSTRACT> CLASS class-name<EXTENDS parent-class-name>
<SUPPORTS supports-interface-clause>
<REQUIRES requires-interface-clause> ;
< / (class-optional-clause)>
<attribute-statements>
<method-declaration-statements>
<method-implementation-blocks>
<event-declaration-statements>
<eventhandler-declaration-statements>
ENDCLASS;
Required Argument
class-name
is the name of a class that you are creating, which can be specified as a one- to fourlevel name.
250
Chapter 13
•
SAS Component Language Dictionary
Optional Arguments
ABSTRACT
is an optional keyword used to define a class as an abstract class. Methods defined
inside an abstract class are not required to have method implementations. Abstract
classes are used to specify a common interface for several classes. An abstract class
can not be instantiated through the _NEW_ operator.
parent-class-name
specifies the parent class of class-name and is specified as EXTENDS parent-classname. Parent-class-name can be specified as a one- to four-level name.
If no EXTENDS clause is supplied, parent-class-name defaults to
SASHELP.FSP.OBJECT.CLASS, which is the parent class of all SAS/AF classes.
supports-interface-clause
lists the interfaces that this class supports. Interfaces can be specified as follows:
SUPPORTSinterface-1<,interface-2...>
The interface names can be specified as one- to four-level names. All of the methods
listed in SUPPORTS must be implemented in the CLASS block.
requires-interface-clause
lists the interfaces required for this class. Interfaces are specified as follows:
REQUIRES interface-1<,interface-2...>
The interface names can be specified as one- to four-level names. The REQUIRES
interfaces are used for the client-server model. For more information, see
“INTERFACE” on page 475.
class-optional-clause
specifies options for the class. Options should be placed inside parentheses following
a / (slash). Separate multiple options with commas. Class options can be any of the
following:
Description=description
is a description of the CLASS entry. This description is used to identify the class
in the Components window. A description that does not match the description of
any other class is required. There is no programmatic validation of the
uniqueness of a description.
MetaClass=class-name
is the four-level name of the CLASS entry that contains the model of a class. The
default MetaClass is SASHELP.FSP.CLASS.CLASS.
attribute-statements
defines the class attributes, which determine how an object will look and behave.
Attributes can either be scalars or arrays. The syntax of a class attribute statement is:
access-scope type var-name< / (attribute options)>;
access-scope
can be one of the following:
'PUBLIC'
specifies that the attribute can be accessed by any SCL program. DECLARE
may be used in place of public scope.
'PRIVATE'
specifies that the attribute can be accessed only from methods in the class
where the attribute is defined.
CLASS 251
'PROTECTED'
specifies that the attribute can be accessed only from methods in subclasses
of the class where the attribute is defined. Since a class can be considered a
subclass of itself, a protected attribute can also be accessed from the class
where it is defined.
type
is the data type of the attribute. NUM, CHAR, LIST, OBJECT or a four-level
class-name are possible values of type.
var-name
is the name of the attribute. You can specify a multi-dimensional array by
providing an array dimension after var-name. For example:
PRIVATE num narray{3, 2, 3};
If an array variable has the same name as a method, the method name has higher
precedence when referencing that array. To avoid ambiguity, use [ ] or { }
instead of ( ) to specify the array reference.
attribute-options
specifies options for a class attribute. List options inside parentheses following
a / (slash). Separate multiple options with commas. Attribute-options can be any
of the following:
AutoCreate='N' | 'Y'
determines whether an SCL list is created automatically when an instance of
the class is created. If AutoCreate='Y' (default), a four-level object name
or SCL list is created depending on the attribute type. If 'N', then a fourlevel object name or SCL list is not created, and the user is responsible for
creating and deleting this list.
Category=category-name
specifies the category for an attribute. Categories organize attributes so that
you can display only attributes for the category. You can create your own
category names. Components that are supplied with SAS software belong to
the following categories:
•
Appearance
•
Data
•
Drag and drop
•
Help
•
Misc (Miscellaneous)
•
Region
•
Size/location
Misc is the default.
Description=attribute-description
specifies the description of the attribute. When you click on an attribute in the
Class Editor, this text is displayed below the list of attributes.
Editable='N' | 'Y'
determines whether attributes can be altered. 'Y' is the default.
If EDITABLE='Y', then the attribute can be set anywhere that it is in scope:
•
If the attribute is defined in class C and it is a public attribute, then it can
be set anywhere.
252
Chapter 13
•
SAS Component Language Dictionary
•
If the attribute is defined in class C and it is a private attribute, then it can
only be set from methods in the class C.
•
If the attribute is defined in class C and it is a protected attribute, then it
can only be set from methods in C and subclasses of C.
If EDITABLE='N', then the ability to set the attribute is restricted based on
its scope:
•
If the attribute is defined in a class C and it is a public attribute, then it
can only be set from methods in C and subclasses of C.
•
If the attribute is defined in class C and it is a protected attribute, then it
can only be set from methods in C.
•
If the attribute is defined in class C and it is a private attribute, it cannot
be set anywhere. (It is effectively a constant.)
Editor=editor-entry-name
specifies a FRAME, SCL, or PROGRAM entry that returns a value. The
Editor= option is available for attributes of all types except OBJECT. If
supplied, the specified entry is displayed and executed by the Properties
window when the ellipsis button (...) in the cell is clicked. The value that is
returned from the entry is displayed in the cell in the Properties window.
Editors are typically FRAME entries that are designed to aid an application
developer in specifying a value for an attribute. For example, for an attribute
called 'textColor' that can be assigned to any hexcolor string, you could
design a FRAME entry window to help the user visually see what the
hexcolor string represents. The window could contain an RGB slider control
with a sample box that shows the color that is being created as a user
manipulates the red/green/blue sliders. In this example, you assign the name
of the FRAME entry as the value of EDITOR=, and this window opens when
a user selects the ... button for the TEXTCOLOR attribute in the Properties
window.
GetCAM=method-name
specifies the custom access method to be executed when the value of the
attribute is queried. Using dot notation on page 132 to query an attribute for
which a getCAM method has been defined may result in side effects. See
“What Happens When Attribute Values Are Set or Queried” on page 135.
InitialValue=initial-values
specifies an initial value for the attribute. This option is valid only for
attributes with types CHAR , NUM, and SCL LIST.For an example of using
an SCL list as an initial value, see “Initializing the Values in an SCL List” on
page 57.
Linkable='N' | 'Y'
determines whether an attribute is linkable from the Properties window. Only
public attributes are linkable. Private and protected attributes are not
displayed in the Properties window. Y is the default.
SendEvent='N' | 'Y'
determines whether an attribute sends an event when modified. When
SENDEVENT='Y', SAS assigns the Event Name, which has the format
“attributeName Changed”, and registers it with the component. Y is the
default. When SENDEVENT='N', no Event name will be registered
CLASS 253
SetCAM=method-name
specifies the custom access method to be executed when the attribute value is
assigned. Using dot notation on page 132 to set an attribute for which a
setCAM method has been defined may result in side effects. See “What
Happens When Attribute Values Are Set or Queried” on page 135.
State='N'|'O'
determines whether the attribute is new or is overridden. N is the default.
ValidValues=valid-values
specifies the values that are valid for the CHARACTER attribute. Use a
space or '/' or ',' to separate the values.
The following options are used for compatibility with Version 6 classes:
Automatic='Y' | 'N'
specifies whether var-name is an automatic instance variable.
IV=V6-instance-variable-name
specifies the name of a Version 6 instance variable.
PureIV='Y' | 'N'
When PureIV='Y', it specifies that var-name is a pure Version 6 instance
variable and that no associated SCOM attribute will be created. N is the
default.
method-declaration-statements
list the class methods.
For method-declaration-statements, use the following syntax:
method-label-name : <access-scope> METHOD<parameter-list>
< / (method-options)>;
method-label-name
can be up to 32 characters and has the same restrictions as an SCL label. By
default, you should treat method-label-name the same as the method name. To
define a more descriptive method name which is over 32 characters, use the
method= option.
access-scope
can be one of the following:
PUBLIC
designates a method that can be inherited by subclasses and accessed
anywhere the corresponding object exists. This is the default.
PRIVATE
designates a method that can be accessed only by methods in the class in
which the method is defined. Private methods will not be inherited by
subclasses of the class.
PROTECTED
designates a method that can be accessed only by subclasses in which the
method is defined. Since a class can be considered a subclass of itself, a
protected method can also be accessed from the class in which it is defined.
parameter-list
For parameter options such as using Input/Output/Update to store the parameter
storage, using “:” operator to specify the parameter type, using Optional= to
specify the varying arguments in the method, and using Return= to specify the
method return type, as well as Arglist= and Rest=, can all be applied in the
parameter list. For more information, see “METHOD (define)” on page 535.
254
Chapter 13
•
SAS Component Language Dictionary
method-options
specify options for a class method. You must put the list inside parentheses that
follow a / (slash). Separate multiple options with commas. The available options
are
Abstract='N' | 'Y'
specifies that the method is an abstract method and does not have an
implementation associated with it. Abstract methods can be declared only in
abstract classes. The default is 'N'.
Description=method-description-string
specifies the description of the method.
Enabled='N'|'Y'
determines whether a method can be temporarily disabled. Y is the default.
Label='method-label'
identifies a method whose label is different from the method-label-name. If
the Label= option exists, the Method= option cannot be used.
Method='method-name'
identifies the method-label-name as the label name and the 'method-name'
will be used for the method reference in the dot notation on page 132 or
CALL SEND routine. Since the 'method-name' is a string, you can extend the
method name up to 256 characters. If the Method= option exists, the
Label= option cannot be used.
Native='/executable-name:n
specifies the name of a system-implemented method. This option is generated
by the CREATESCL function.
SCL | Entry=four-level-entry-name-string
identifies the entry that contains the USECLASS block that implements the
method. This option is required when the method is not implemented in the
SCL entry that contains the CLASS statement block.
Signature='N'|'Y'
determines whether the method has a signature. Y is the default. All methods
in Version 6 classes have Signature='N'. Adding parameter-list and
removing Signature='N' for each method will cause the SCL compiler to
generate signatures for that method. Signature='Y' is required for method
overloading.
State='O'|'N'
determines whether the method has been overridden or is new.
Forward='N'|'Y'
determines whether the method can be forward referenced when
Forward='Y'. The SCL compiler is a one-pass compiler and will report
errors when referencing a method that has not been defined in the current
class. Using Forward='Y' will allow the SCL compiler to suppress the
error messages and delay validation of the forward methods which are
required to be defined later in the current class. If the forward method is not
defined before the ENDCLASS statement, the SCL compiler will report the
error. N is the default. This option can be used for methods calling each other.
ArgDesc1 | ArgDesc2 |...| ArgDescN =each-argument-description-string
specifies each argument description. This option is used for documenting the
parameters.
CLASS 255
ReturnDesc=return-argument-description-string
specifies the return argument description. This option is used for
documenting the return parameter.
method-implementation-blocks
contain any SCL statements for the defined methods. These statements perform the
operations of the method.
event-declaration-statements
define the class events. Declare the events as follows:
EVENT event-string-name < / (event-options)>;
event-string-name
is the name of the event you are declaring.
event-options
specifies options for the event. You must put the list inside parentheses that
follow a / (slash). Separate multiple options with commas. Event options can be
Description=event-description
specifies the description of the event.
Enabled='N'|'Y'
determines whether an event can be temporarily disabled. Y is the default.
Method=string
identifies the method that handles the event.
Send='Manual'|'After'|'Before'
determines when the object sends the event.
After is the default.
eventhandler-declaration-statements
define the event handler to be executed after the events are triggered. The event
handler is an SCL method that handles the event. Declare the event handler as
follows:
EVENTHANDLER eventhandler-name< / (eventhandler-options)>;
eventhandler-name
is the name of the event handler of an SCL class method that you are declaring.
eventhandler-options
specifies options for the event handler. You must put the list inside parentheses
that follow a / (slash). Separate multiple options with commas. Event handler
options can be
Description=eventhandler-description
specifies the description of the event handler.
Enabled='N'|'Y'
determines whether an event handler can be temporarily disabled. Y is the
default.
Event=event-name
specifies the name of the event.
Method=string
identifies the method that handles the event.
Sender='_SELF_' | '_ALL_'
identifies the location of the sender to trigger the event handler. When
Sender='_SELF_', the event handler will only listen to events from the
256
Chapter 13
•
SAS Component Language Dictionary
class itself. When Sender='_ALL_', the event handler will listen to events
from any other class. Using the method _addEventHandler, you can
dynamically add a sender to trigger the event.
Details
The CLASS statement enables you to use SCL to create a class and to define attributes,
methods, events and event handlers for the class. The CLASS block is especially useful
when you need to make many changes to an existing class such as adding signatures to
an existing class, or when you want to create a class in batch mode. Using the CLASS
block provides the advantages of error detection at compile time and improved
performance during run time. It also enables you to use short-cut notation. Instead of
using _SELF_.attribute or _self.method(...) to reference the name of a class attribute or a
class method, you simply specify the attribute or method name. This makes programs
easier to read and maintain. In addition, you can overload method definitions, which
means that multiple methods can have the same name, but have different numbers and
types of parameters.
The program block that defines a class starts with a CLASS statement and ends with an
ENDCLASS statement. A CLASS block can contain statements that define attributes,
methods, events, event handlers and even METHOD statement blocks implementing the
operations for methods. You can also put the METHOD statements that implement class
methods in another SCL entry when you use the SCL= method option to specify the
name of that entry. Then, in the SCL entry that is specified with SCL=, define the
methods for the class within a USECLASS statement block. Defining methods in a
separate entry is useful for enabling class methods to be created, tested, or maintained by
multiple application developers. For more information, see “METHOD (execute)” on
page 533.
To create a class from an SCL entry that contains a CLASS block, either issue the
SAVECLASS command or select File ð Save Class from the SCL Source Editor. Both
are equivalent to using the Class Editor to interactively create a CLASS entry. However,
the Class Editor provides a graphical view of the class, whereas the CLASS statement in
SCL provides a language view of the class.
Do not declare the _SELF_, _FRAME_, _CFRAME_, _METHOD_, or _EVENT_
system variables inside a CLASS or USECLASS block. SCL automatically sets these
values when it is running methods that are defined in CLASS or USECLASS blocks.
Redefining any of these system variables can introduce unexpected behavior.
In methods that are defined in a CLASS statement block, all references to the methods
and the attributes of the class can bypass two-level references to _SELF_.attribute and
_SELF_.method(...). Because these methods are defined within the class, the SCL
compiler can detect whether an undefined variable is a local variable or a class attribute.
You can also use the _super method in method code inside a CLASS statement block
without having to specify either an object identifier or the method whose super method
you are calling. You can use the _super method to call any method. For example, to
invoke the super ADD method, you would use
_super.add();
To override the _init method, you must first call the super _init method before overriding
the _init method. For example:
_super._init();
...statements that define the
overridden _init method ...
Any SCL function or routine can be called inside a METHOD statement block that is
inside a CLASS block. Outside the METHOD statement block, only class attribute
CLASS 257
statements, event statements and event handlers are allowed in a CLASS block. Other
than the IMPORT statement, no SCL statements can be written outside the CLASS
block.
METHOD blocks can include labeled sections. However, labeled sections that are
outside a method block must be re-coded as PRIVATE methods, and the LINK
statements that call them must be changed to method calls. This programming style will
make your applications more consistent with the object-oriented paradigm.
If a local variable that is defined in a METHOD block has the same name as a class
attribute, SCL gives precedence to the local variable. If a class method has the same
name as any SCL-supported function, SCL gives precedence to the function. If an
attribute array has the same name as a class method, SCL gives precedence to the
method. It is probably best to avoid using the same name for multiple local variables,
class attributes, method names or arrays to avoid problems.
The CLASS statement also enables you to define method definitions for overloading
methods, which means that multiple methods have the same name. Methods that have
the same names are allowed in a CLASS block only if the signatures, or parameter
numbers or types, are different. For example, a class can have one COMBINE method
that has numeric parameters and adds parameter values, and another COMBINE method
that has character parameters and concatenates parameter values.
Inheritance from multiple classes is not supported in class syntax, but is allowed with
interface syntax. For more information, see “INTERFACE” on page 475.
Examples
Example 1: A CLASS Block with Method Implementation
This example defines the Arith class, a subclass of Sashelp.Fsp.Object.class, and
implements the methods in the CLASS entry. The example shows the METHOD
statements using the RETURN= option and then RETURN statements returning values
to the caller.
class work.classes.arith.class;
public num total;
public char catstr;
/* A method that adds numeric values */
add: public method n1:num n2:num return=num;
total = n1 + n2;
return (total);
endmethod;
/* A method that concatenates */
/* character values
*/
concat: public method c1:char c2:char return=char;
catstr = c1 || c2;
return (catstr);
endmethod;
endclass;
Example 2: A CLASS Block without Method Implementation
This example defines the Combine class and specifies the SCL entry in which the
methods are implemented. The class uses overloaded COMBINE methods, one to
process numeric values and another to process character values. The code that
implements the methods is defined in a USECLASS block.
class work.classes.combine.class;
258
Chapter 13
•
SAS Component Language Dictionary
public num total;
public char catstr;
combine: public method n1:num n2:num return=num
/ (scl='work.classes.combine.scl');
combine: public method c1:char c2:char
return=char
/ (scl='work.classes.combine.scl');
endclass;
Here is the USECLASS block that contains the method implementations for
WORK.CLASSES.COMBINE.CLASS:
useclass work.classes.combine.class;
combine: public method
n1:num n2:num return=num;
total = n1 + n2;
return (total);
endmethod;
combine: public method
c1:char c2:char return=char;
catstr = c1 || c2;
return (catstr);
endmethod;
enduseclass;
Example 3: Definition of a Class
This example imports the Collection class, which is provided with SAS/AF software,
and shows several forms of attribute declarations, method declarations, and overloading
methods. Attributes list1 and list2, which define SCL list initialization, can also be found
in this example.
import sashelp.fsp.collection.class;
class work.classes.myclass.class
extends sashelp.fsp.object.class
/ (description = 'my first class file');
/* simple attribute with no options */
public num num1;
/* Attribute with options */
public num num2
/ (description = 'second numeric attribute',
initialvalue= 3,
validvalues = '1 2 3');
/* Another attribute with options */
public char string1
/ (editable = 'n', linkable = 'n',
initialvalue = 'abc');
/* SCL List initializations:items without name*/
public list list1
/ (InitialValue={1, 2, 3, 'abc', 'def', 4, 5, 6}
);
/* SCL List initializations:Items with name.*/
/* Address is a sublist of list2
*/
public list list2
/ (InitialValue={name='John Doe', Number=100,
Address={State='NC', CITY='CARY'},
Office='Bldg Z'} )
/* Private array attribute */
CLASS 259
private num arr(3) ;
/* Private list attribute
*/
private list list;
/* Protected collection attribute */
protected collection coll;
/* public method m0 */
m0: Public method
/* External method implementations */
/ (scl='mylib.classes.b.scl',
label = 'M0',
description='test method m0');
/* Public method m1
*/
/* with no method options */
m1: public method ;
...more SAS statements...
endmethod;
/* Private overloading method m1 */
/* with numeric parameter
*/
m1: private method n: num;
...more SAS statements...
endmethod;
/* Protected overloaded method m1.
* Method implementations should be placed in
* work.classes.c.scl */
m1: protected method s: char
/* external method implementation */
/ (scl = 'work.classes.c.scl');
/* Other public method */
m2: method return=num;
...more SAS statements...
return (1);
endmethod;
/* Private method */
m3: private method;
...more SAS statements...
endmethod;
endclass;
Example 4: Illustrating Short-Cut References
This example shows how to use the _super method as well as short-cut references to
_SELF_:
CLASS work.classes.another.class;
Public Num n1;
Public Num n2;
Public Char c1;
Public Char c2;
Public Num m(3);
_Init: method / (State='O');
DCL Num n2;
DCL Char c2;
/* Equivalent to call super(_init); */
_SUPER();
/* Equivalent to _SELF_.N1 = 1
*/
n1 = 1;
/* Local variable N2 dominates class */
260
Chapter 13
•
SAS Component Language Dictionary
/* attribute N2
*/
n2 = 1;
m{1} = abs(n2);
/* Uses { to avoid ambiguity
*/
/* Equivalent to _SELF_.C1 = 'a' */
c1 = 'a';
/* Local variable C2 dominates */
/* class attribute C2
*/
c2 = 'a';
endmethod;
/* commonly used method can be PRIVATE */
Common: Private Method a:Num;
...more SCL statements...
a = a + 1;
endmethod;
M: method;
/* Equivalent to
*/
/*
if _SELF_.N1 > 0 then */
if n1 > 0 then
/* Equivalent to
*/
/*
_SELF_.N1 + 1; */
n1 + 1;
common(n1);
endmethod;
/* Method M1 with numeric parameter */
M: method n: Num;
/* Equivalent to _SELF_.M(); */
M();
common(n1);
endmethod;
endclass;
Example 5: Illustrating a Set Custom Access (setCAM) Method
This example shows a setCAM method, M1, which will be invoked when the attribute N
is modified in the _init method.
Class work.mycat.camDemo.class;
Public num n / (initialValue = 5,
setCam='m1');
_init: Method / (State='O');
_super();
n = 3;
EndMethod;
m1:
Method nParm:Num;
/* - nParm is input value of attribute n */
nParm = nParm + 100;
/* nParm is output value of attribute n */
EndMethod;
EndClass;
To reference the camDemo class, you can code the following program:
Init:
DCL camDemo obj = _new_ camDemo();
obj.n = 7;
/*
Using the SCL debugger to trace the sequence
*
of this program, you will find the value
CLASS 261
*
of obj.n = 107 */
put obj.n=;
Return;
Example 6: Illustrating User-defined Events and Event Handlers
This example shows a system-defined event, 'n Changed', which will be automatically
generated to associate with the attribute N. An event handler, M1, which is associated
with the 'n Changed' event is also written and will be executed when the attribute N is
modified. Another user-defined event, 'myEvent', is created by the EVENT statement.
The associated event handler, M2, will be executed when an explicit _sendEvent method
is executed.
Class work.mycat.eDemo.class;
Public num n; /* sendEvent='Y' is default*/
Public char c / (sendEvent='N');
Event 'myEvent'
/ (method='m2');
EventHandler m1
/ (Sender='_SELF_',
Event='n Changed');
EventHandler m2
/ (Sender='_ALL_',
Event='myEvent');
m1: method a:list;
Put 'Event is triggered by attribute N';
endMethod;
m2: method a:string b:num ;
Put 'Event is triggered by _sendEvent';
return (100);
endMethod;
EndClass;
You could use the following program to trace the control sequence of the event handler
by using the SCL debugger.
init:
DCL eDemo obj = _new_ eDemo();
obj.n = 3; /* will trigger the m1 */
obj._sendEvent('myEvent','abc',3);
Return;
Example 7: Illustrating Forward Method, Optional= and ArgList=
This example shows how to use the method option Forward='Y' to write a method, M1,
which can invoke another method, M2, defined after the current method, M1. Without
the Forward='Y' option, the SCL compiler will issue an error. The M1 method contains
Optional=, which actually includes two overloading methods.
Class mylib.mycat.forward.class;
m2: Method n:num c:char Return=Num / (Forward='Y');
m1: Method n1:num Optional=n2:num Arglist=argList
Return=Num;
DCL Num listLen = listlen(argList);
DCL Num retVal;
if (listLen = 1) then
retVal = m2(n1, 'abc');
else if (listLen = 2) then
262
Chapter 13
•
SAS Component Language Dictionary
retVal = m2(n2, 'abc');
Return(retVal);
EndMethod;
m2: Method n:num c:char Return=Num;
Return(n+length(c));
EndMethod;
EndClass;
See Also
•
“ARRAY” on page 220
•
“CREATESCL” on page 289
•
“ENDCLASS” on page 342
•
“METHOD (define)” on page 535
•
“USECLASS” on page 706
CLEARLIST
Clears the items from an SCL list without deleting the list and optionally clears all sublist items
Category:
List
Syntax
rc=CLEARLIST(list-id<,recursively>);
Required Arguments
rc
indicates whether the operation is successful:
0
successful
≠0
not successful
Type: Numeric
list-id
is the identifier of the list that contains the items to clear. An invalid list-id produces
an error condition.
Type: Numeric or List
Optional Argument
recursively
indicates whether to recursively clear all the list's sublists as well as all sublists of its
sublists.
'D'
Clears and deletes sublists recursively.
'N'
Sublists are not cleared. (This is the default.)
'Y'
Clears sublists recursively.
CLOSE
263
Type: Character
Details
CLEARLIST clears all the items from the SCL list identified by list-id. The list is not
deleted, but its length is reduced to 0. If recursively is 'Y', then all the list's sublists,
including sublists of sublists, are also cleared.
CAUTION:
Before you clear a list recursively, make sure it is not needed by other parts of
the SCL program. The recursively option clears all of a list's sublists, even if they
are referenced in other SCL lists or by other SCL variables.
An error condition results if
•
the list has the NOUPDATE or FIXEDLENGTH attribute.
•
any item in the list (or in its sublists, if recursively is 'Y') has the NODELETE
attribute.
•
recursively is 'Y', and any sublist has the NOUPDATE or FIXEDLENGTH
attribute.
•
list-id is a component or class identifier.
If an error condition results, no further items or sublists are cleared.
Example
Clear all sublists from an existing list identified by MYLIST without deleting items that
are not sublists:
/* Copy the list. */
cp=copylist(mylist);
/* Clear the entire list, including sublists
/* that also appear in CP.
rc=clearlist(mylist,'Y');
/* Copy the old list data. */
/* Sublists have been cleared. */
mylist=copylist(cp,'N',mylist);
/* Delete the copied list. */
rc=dellist(cp);
See Also
•
“COPYLIST” on page 284
•
“DELITEM” on page 310
•
“DELLIST” on page 311
•
“DELNITEM” on page 313
•
“SETLATTR” on page 662
CLOSE
Closes a SAS table
Category:
SAS Table
*/
*/
264
Chapter 13
•
SAS Component Language Dictionary
Syntax
sysrc=CLOSE(table-id);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
table-id
is the identifier that was assigned when the table was opened. A table-id value of
-999 closes all tables that were opened with OPEN. If table-id is invalid, the
program halts.
Type: Numeric
Details
Close all SAS tables as soon as they are no longer needed by an application. You do not
need to open and close a SAS table in each program of an application. If an application
contains several programs that use the same table, the first program can open the table
and can use the parameter passing mechanism with the DISPLAY routine or method
calls to make the table identifier value available to other programs.
Example
Use OPEN to open a SAS table. If the table opens successfully, as indicated by a
positive value for the PAYID variable, then use CLOSE to close the PAYROLL table.
payid=open('payroll','u');
...SCL statements...
if (payid>0) then payid=close(payid);
See Also
“OPEN” on page 574
CLRFLD
Clears the value from variables whose values match a specified value
Category:
Control or Field
Syntax
CALL CLRFLD(pattern,variable-1<, . . . ,variable-10>);
COLORLIST 265
Required Arguments
pattern
is the character string to match.
Type: Character
variable-1, . . . , variable-10
names up to ten character variables. If the value of a variable in this list matches
pattern, then that value is cleared.
Type: Character
Details
Variables in the variable list whose values do not match pattern exactly are not changed.
No error occurs if there are no matches.
Example
Clear the value of any variable in the group SYM1 through SYM5 whose value is BLUE:
call clrfld('blue',sym1,sym2,sym3,sym4,sym5);
See Also
“SETFLD” on page 655
COLORLIST
Displays a selection list of the names of a device's valid colors and returns user selections
Category:
Selection List
Syntax
selections=COLORLIST(color-set,num-sel<,message <,autoclose> > );
Required Arguments
selections
contains one or more user selections from the list. Multiple selections are separated
by blanks. By default, selections is 200 bytes long. To accommodate values longer
than 200 bytes, you should explicitly declare selections with a longer length.
Type: Character
color-set
specifies the set of colors to display in the selection list:
device
specifies the name of a SAS/GRAPH device. If device is supplied, the
selection list includes only the colors that are valid for the specified
device, and an All... choice to display all possible colors. Device
can be the name of a monitor, plotter, printer, or camera. This name
can be up to eight characters long and must be specified within quotes.
If the device entry is not found, the list contains all possible colors
without regard to whether the device supports them.
266
Chapter 13
•
SAS Component Language Dictionary
'?'
opens the Color Selector window in which a user can design a color.
Only one color can be defined, so num-sel is ignored. For additional
information, use the window's online help.
Type: Character
num-sel
is the maximum number of items that a user can select from the list. To display the
list for information purposes only (no selections allowed), specify 0. To specify an
unlimited number of selections, use a value such as 9999 that is larger than the
number of available selections. A user cannot make a number of selections that
exceeds the number of items in the list.
Type: Numeric
Optional Arguments
message
is the message text to display above the selection list. The default message tells users
to make up to the number of selections specified in num-sel.
Type: Character
autoclose
specifies whether the selection list window closes automatically after a user makes a
selection when only one choice is allowed:
'Y'
closes the window automatically. (This is the default.)
'N'
leaves the window open until the user explicitly closes it.This option is
ignored when num-sel is not 1.
Type: Character
Details
By default, the message above the selection list asks the user to make num-sel selections.
Also by default, the selection list window closes when the user makes a choice and
presses ENTER if the selection list allows only one choice.
The FIND item in the selection list window enables you to specify characters that a
value in the list contains. If the value is found, it is displayed as selected. If the value is
not found, a message is displayed in the selection list window.
You can provide default values that will be initially selected when the color selection list
is displayed. To do this, assign the values to the selections variable before calling
COLORLIST.
If a user closes the selection list window without making a selection, COLORLIST
returns a blank value unless there was an initial value for the selections variable before
COLORLIST was called.
Selections from the window can be placed in the current result list, if one is available.
The current result list is a special SCL list that is automatically filled with the values that
are selected from a selection list. To use a current result list, use the MAKELIST
function to create it, and use the CURLIST function to designate it as the current result
list. The current result list must exist before you call the COLORLIST function.
You can use COLORLIST to enable a user to interactively design the RGB components
for a color. If a user designs a color that is not supported on that device, SCL uses the
closest color that is supported.
COMAMID
267
When COLORLIST is invoked, the current result list is cleared. After COLORLIST is
invoked, the result list contains one element for each selected color name. The selections
can be retrieved by using GETITEMC.
Example
Display a list of devices of type MONITOR that are available in the catalog
SASHELP.DEVICES and allow users to select a device. Users can choose up to four
colors from the selection list. If no device is chosen, display a list of all possible colors.
usrdev=devlist('sashelp.devices','monitor',
'Select a device. ');
device=substr(usrdev,41,8);
devcolor=colorlist(device,4);
Use a current result list to process multiple selections:
listid=makelist();
rc=curlist(listid);
selection=devlist('sashelp.devices','monitor',
'Select a device.');
device=substr(selection,41,8);
devcolor=colorlist(device,4);
n=listlen(listid);
do i=1 to n;
color=getitemc(listid,i);
put color=;
end;
Display a color selection dialog window:
color=colorlist('?',1,'Design a color for the
bars');
See Also
•
“CURLIST” on page 293
•
“DEVLIST” on page 318
COMAMID
Returns the list of communications access methods for an operating system
Category:
SAS System Option
Syntax
comamids=COMAMID(options);
Required Arguments
comamids
are the communications access methods (comamids) for the operating system or for
SAS/SHARE software or SAS/CONNECT software, if they are requested. Multiple
values are separated by blanks.
268
Chapter 13
•
SAS Component Language Dictionary
Type: Character
options
requests comamid values that are supported by SAS/SHARE software or
SAS/CONNECT software for your operating system:
'S'
requests comamid values that are supported by SAS/SHARE software.
'C'
requests comamid values that are supported by SAS/CONNECT software.
Details
COMAMID provides a list of communication access method values for a user's
operating system. If no value is provided for options, then all comamid values for the
operating system are returned.
You can display the list to application users by using other SCL features. For example,
you can display the values in a list box by specifying that the source of list box values is
the variable that you used as the return value for COMAMID.
Note: COMAMID verifies communication access method values so that if the module
to support a value has not been installed, that value is not returned in the string of
comamid values.
Examples
Example 1: Finding the Comamids for an Operating System
Find out which comamids are valid for the operating system:
INIT:
comamids=COMAMID();
put comamids=;
return;
This example produces the following output on an HP-UX system:
COMAMIDS= TCP
Example 2: Finding Comamids for SAS/SHARE Software
Find out which comamids are supported by SAS/SHARE software:
INIT:
comamids=COMAMID('S');
put 'Comamids for SAS/SHARE are 'comamids=;
return;
This example produces the following output on an HP-UX system:
Comamids for SAS/SHARE are COMAMIDS=TCP
COMPAREARRAY
Allows you to compare two arrays for size and data equality
Category:
Array
COMPAREARRAY
269
Syntax
rc=COMPAREARRAY(array1,array2);
Required Arguments
rc
indicates whether the two arrays match.
0
arrays match
1
arrays do not match
Type: Numeric
array1
is one of the two arrays to be compared.
Type: Array
array2
is one of the two arrays to be compared.
Type: Array
Details
The COMPAREARRAY function allows you to compare two arrays for size and data
equality. To be considered equal, the arrays must:
•
have the same number of dimensions
•
be of the same type
•
have the same bounds
•
have the same values in each element.
Comparisons
This example compares several different arrays.
DCL num n1(5) n2(5,5) n3(*) n4(5) n5(*,*);
DCL char c1(5);
DCL num rc;
rc = comparearray(n1,n2); put rc=;
rc = comparearray(n1,c1); put rc=;
rc = comparearray(n1,n3); put rc=;
n3 = makearray(3);
rc = comparearray(n1,n3); put rc=;
rc = redim(n3,5);
rc = comparearray(n1,n3); put rc=;
do i=1 to 5;
n1[i] = i;
n4[i] = i;
end;
rc = comparearray(n1,n4); put rc=;
rc = copyarray(n2,n5);
rc = comparearray(n2,n5); put rc=;
rc = delarray (n3); rc = delarray (n5);
The output for this code would be:
270
Chapter 13
•
SAS Component Language Dictionary
rc=1
rc=1
rc=1
rc=1
rc=0
rc=0
rc=0
See Also
•
“COPYARRAY” on page 282
•
“DELARRAY” on page 307
•
“MAKEARRAY” on page 525
•
“Introduction to SCL Arrays” on page 41
COMPARELIST
Compares two SCL lists
Category:
List
Syntax
rc=COMPARELIST(list1-id,list2-id<,options> );
Required Arguments
rc
contains the return code for the operation:
0
The lists match.
1
The lists do not match.
list1–id, list2–id
contain the identifiers for the two SCL lists to be compared.
Optional Argument
options
specify one or more comparison options. Use a space to separate multiple options.
The available options are:
NAME (Default)|NONAME
determine whether the comparison is performed on the names of list items that
are in the same position in both lists. NONAME does not compare item names.
NOHONORCASE (Default)|MIXEDCASE
determine whether the comparison is performed on the uppercase or mixed case
values of all item values and names. NOHONORCASE compares the uppercase
values of item names and values. MIXEDCASE compares mixed case names and
values.
CONTENTS
271
ITEM (Default)|NOITEM
determine whether the comparison is performed on the values of list items that
are in the same position in both lists. NOITEM does not compare list values.
NODUMP (Default)|LONGDUMP|SHORTDUMP
determine the extent to which differences are reported. NODUMP produces no
messages. LONGDUMP displays all differences in the LOG window.
SHORTDUMP displays the first five differences.
Details
COMPARELIST enables you to compare the information in two SCL lists. This
comparison can include item names, values, or both. Names and items can be compared
in mixed case.
Example
Compare the item names and values in OLDLIST and NEWLIST. If the lists are not the
same, write all the error messages to the SAS log. If the lists are the same, delete
OLDLIST.
rc=comparelist(oldlist,newlist,'name item nohonorcase
if rc=0 then
rc=dellist(oldlist);
else do;
...SCL statements to run
when the lists do not match...
end;
longdump');
CONTENTS
Displays the attributes of a SAS table
Category:
Catalog and SAS Table
Syntax
rc=CONTENTS(SAS-table<,mode>);
Required Arguments
rc
contains the return code for the operation:
0
The attributes of the specified table were displayed.
≠0
An error or warning condition occurred during the operation.
Type: Numeric
SAS-table
is the name of the SAS table. (SAS data set options are ignored in this argument.)
The name of the data set would have to include the #nnn number of the generation
set. For example to view the third generation data set of WORK.ONE:
272
Chapter 13
•
SAS Component Language Dictionary
rc=contents('work.one#003');
Type: Character
Optional Argument
mode
specifies whether the information can be modified:
'B'
displays the Properties window for browsing only.
'E'
allows information in the Properties window to be modified. (This is the
default.) If member-level locking is not available, then the Properties
window is displayed in BROWSE mode instead. Any value that begins
with a character other than B or b also selects EDIT mode. Type: Character
Details
The CONTENTS function opens the Properties window, which enables an application
user to browse or modify column names, formats, informats, and labels of a SAS table.
By default, the Properties window is opened in edit mode. However, if the specified
table is currently open, then you must specify B for mode.
Initially, General Properties (that is, attributes, but not column names) are listed in the
Properties window. To change the value of an attribute, do the following:
1. Click the mouse menu button on the attribute that you want to change and then click
on Modify.
2. In the dialog window that appears, make the desired changes to the text.
To change a column name, do the following:
1. Click on the down arrow at the upper right corner of the window. The menu that
appears contains information about the table, including column names. Select the
column name that you want to change.
2. Click the mouse menu button on the column name that you want to change, and then
select Modify.
3. In the dialog window that appears, make the desired change to the column name.
Example
Display the attributes for the table MYLIB.HOUSES:
if (contents('mylib.houses')) then
do;
_msg_=sysmsg();
...SCL statements to handle case where
contents cannot be displayed...
end;
CONTINUE
Stops processing the current DO loop and resumes with the next iteration of that DO loop
CONTINUE 273
Category:
Note:
Control Flow
SAS Statement with limitations in SCL
Syntax
CONTINUE;
Details
The CONTINUE statement is provided in SCL to control the execution of DO loops.
When you need to force the statements in a DO loop to stop executing, you can use the
CONTINUE statement to stop executing successive statements in a DO loop, and to
move back up and re-execute the DO loop, starting with the header statement.
Note: In DATA step code, the CONTINUE statement stops processing only the current
DO loop. In SCL code, the CONTINUE statement stops processing the current DO
loop or DO group, whichever is closest. For example, suppose your code contains a
DO loop that contains DO groups:
do n=1 to 5;
/* DO loop */
if n=2 then do; continue; end;
put n=;
end;
/* DO group */
When this code is compiled and run as part of an SCL program, the output is:
n=1
n=2
n=3
n=4
n=5
When this code is submitted as part of a DATA step, the output is:
n=1
n=3
n=4
n=5
See “DO” on page 333 for more information on DO groups and DO loops.
When you use DO WHILE and DO UNTIL statements, use caution to prevent the
CONTINUE statement from forcing the program into an infinite loop. For example, the
following statements produce an infinite loop because the value of the variable I never
exceeds 2. When I has the value of 2, the IF statement always causes a branch around the
next two SCL statements.
/* This example causes an infinite loop */
INIT:
i=1;
do while (i<1000);
if mod(i,2)=0 then
continue;
sum+i;
i+1;
end;
return;
See the documentation for the CONTINUE statement in SAS Statements: Reference for
more information.
274
Chapter 13
•
SAS Component Language Dictionary
Example
Count the number of females in the SAS table WORK.PERSONEL and display their
average age. WORK.PERSONEL contains the column GENDER, which contains the
values F for female and M for male, as well as the column AGE, which contains numeric
values for age. The display window contains two numeric controls: AVGAGE and
FEMALES. If the value of GENDER is not F (female), then the CONTINUE statement
skips the other statements and returns to the DO WHILE statement to read the next row.
The results are displayed in the application window, although the individual records are
not displayed.
INIT:
females=0;
total=0;
persnlid=open('personel');
call set(persnlid);
/* Process rows until all the */
/* rows are read. */
do while (fetch(persnlid) ne -1);
/* Skip males when processing. */
if gender ne 'F' then
continue;
females+1;
total+age;
end;
/* Display the results in the fields */
/* FEMALES and AVGAGE. */
avgage=total/females;
return;
MAIN:
...other SCL statements...
return;
TERM:
rc=close(persnlid);
return;
See Also
•
“DO” on page 333
•
“LEAVE” on page 494
CONTROL
Controls the execution of labeled program sections and the formatting of submit blocks
Category:
Note:
Control Flow
SAS Statement with limitations in SCL
Syntax
CONTROL options;
CONTROL
275
Required Argument
options
specify the type of control for program statements. The available options are
described below. You can use one or more options.
Type: Character
ALLCMDS | NOALLCMDS
NOALLCMDS is in effect by default. Global or procedure-specific commands
execute immediately without executing the SCL program. The program cannot
intercept any procedure-specific commands that are issued in the application. Use
CONTROL ALLCMDS to enable SCL to intercept procedure-specific or custom
commands that are issued in the application. You can use the NEXTCMD routine
to ignore invalid commands. Use CONTROL NOALLCMDS to restore the
default behavior.
ALLCMDS provides the same functionality as the ALWAYS option and enables
a program to intercept custom commands. In addition, ALLCMDS allows an
SCL program to intercept procedure-specific commands.
In PROGRAM entries, ALLCMDS combines the effects of ENTER and ERROR
and forces statements in the MAIN section to execute even if a user issues
commands that are not recognized by the procedure.
In FSEDIT applications, ALLCMDS and ALWAYS have the same functionality,
and both enable an SCL program to intercept any procedure-specific or custom
commands.
When ALLCMDS is specified, statements execute in the MAIN section before a
command that is issued with the EXECCMD routine. This behavior could
introduce an infinite loop. Either execute the EXECCMD routine conditionally or
specify the command using EXECCMDI with the NOEXEC parameter.
FSVIEW applications ignore these options.
ALWAYS | NOALWAYS
NOALWAYS is in effect by default. The MAIN section executes only when a
user modifies a window variable with a valid value and then presses either
ENTER or a function key. Use CONTROL ALWAYS to force statements in the
MAIN section to execute even if a user issues commands that are not recognized
by the procedure. ALWAYS combines the effects of ENTER and ERROR.
ALWAYS can be used if your application supports custom commands. When
ALWAYS is specified, FSEDIT applications execute statements in the MAIN
section before handling a command that is issued with the EXECCMD routine.
This behavior could introduce an infinite loop. Either execute the EXECCMD
routine conditionally or specify the command using EXECCMDI with the
NOEXEC parameter.
FSVIEW applications ignore this option.
ASIS | NOASIS
NOASIS is in effect by default. SCL formats submit-block code and eliminates
unnecessary spaces and line breaks. Use CONTROL ASIS so that submit blocks
are submitted without formatting. You must use this option when the position of
elements in the SAS code is important (for example, if you are submitting a
DATALINES statement with a DATA step). ASIS is more efficient than
NOASIS because it reduces the time spent on formatting.
276
Chapter 13
•
SAS Component Language Dictionary
BREAK label | NOBREAK
NOBREAK is in effect by default. If a program interrupt occurs while the SCL
statements are executing, a window opens and asks the user whether program
execution should resume (that is, ignore the interrupt) or the program should quit.
If a user chooses to quit execution, no more statements are executed for the
current program, and control returns to the calling program. Use CONTROL
BREAK so that you can specify a labeled section to which control passes if an
interrupt or break condition occurs while the SCL statements are executing.
Label is the program label of the section to execute after the current statement
finishes execution. This labeled section can include SCL statements that report
status and handle the interrupt. Use the _STATUS_ system variable to control
execution such as H to halt and R to resume.
A program can contain any number of CONTROL BREAK statements. For
example, there can be one in each of the INIT, MAIN, and TERM sections or in
any other labeled section. When a CONTROL BREAK statement executes, any
previous CONTROL BREAK statement is overwritten so that only one is in
effect at a time.
Use NOBREAK to restore the default behavior. NOBREAK clears the current
CONTROL BREAK specification.
FSVIEW applications ignore this option.
HALTONDOTATTRIBUTE | NOHALTONDOTATTRIBUTE
HALTONDOTATTRIBUTE is in effect by default. If SCL detects an error in the
dot notation used in your application, the application halts execution. If you
specify NOHALTONDOTATTRIBUTE, the application will continue to execute
when errors are detected in the dot notation, but the results will be unpredictable.
See “Accessing Object Attributes and Methods with Dot Notation” on page 132
for more information.
ENDSAS | NOENDSAS
NOENDSAS is in effect by default. When a user issues the ENDSAS or BYE
command, the TERM sections of SCL programs in the current execution stack do
not execute. This is called an ENDSAS event. Use CONTROL ENDSAS to force
execution of the TERM section in an SCL program when an ENDSAS event
occurs. ENDSAS has no effect on the _term method.
With NOENDSAS in effect, neither SUBMIT blocks nor SCL statements that
call another entry are executed from the TERM section. Because the execution of
a method or the setting of an attribute often involves calling another entry, you
may find that updates to an object made from the TERM section are not
executed.
ENDAWS | NOENDAWS
NOENDAWS is in effect by default. When a user ends a SAS session by
selecting the system closure menu in a FRAME entry that is running with the
Application Work Space (AWS), the TERM sections of SCL programs in the
current execution stack do not execute. This is called an ENDAWS event. Use
CONTROL ENDAWS to force execution of the TERM section in an SCL
program when an ENDAWS event occurs. ENDAWS has no effect on the _term
method.
With NOENDAWS in effect, neither SUBMIT blocks nor SCL statements that
call another entry are executed from the TERM section. Because the execution of
a method or the setting of an attribute often involves calling another entry, you
may find that updates to an object made from the TERM section are not
executed.
CONTROL
277
ENTER | NOENTER
NOENTER is in effect by default. The MAIN section executes only when a user
modifies the value of a window variable and then presses either ENTER or a
function key that is recognized by the procedure. Use CONTROL ENTER to
force MAIN to execute when a user presses the ENTER key or a function key
without modifying a window variable.
In FSVIEW applications, this option has an effect only if the cursor is on a valid
row when ENTER or a function key is pressed.
ERROR | NOERROR
NOERROR is in effect by default. Statements in MAIN do not execute if a
control or field contains a value that causes an attribute error. Thus, some
statements in MAIN do not execute if multiple fields are in error and a user has
not modified all of these fields. Use CONTROL ERROR to force statements in
MAIN to execute even if the window contains fields that are in error.
If you use ERROROFF to remove the error status from a continued portion of a
field in an FSEDIT application, then you must also use a CONTROL ERROR
statement in the program. If a user does not type in the continued portion of the
field and the program does not have a CONTROL ERROR statement, the error
flag is not removed from the continued portion of the field. As a result, the
default error message may be displayed, saying that a data value is not valid.
LABEL | NOLABEL
NOLABEL is in effect by default for PROGRAM and SCREEN entries. MAIN
executes after any window variable is modified. Use CONTROL LABEL to
force sections that are labeled with a window variable name (called window
variable sections) to execute before MAIN executes. For FRAME entries,
CONTROL LABEL is the default.
Statements in a window variable block execute after the associated window
variable is modified, but only if the value does not introduce an error. That is, the
value must satisfy any attributes that have been defined for the window variable.
Statements in MAIN do not execute until statements in all the window variable
sections for modified fields execute successfully. The sequence for executing
window variable sections is determined by the physical position of the field in
the window from left to right and from top to bottom.
If a field modification introduces an attribute error, the associated window
variable section does not execute. However, other window variable sections for
modified window variables do execute. To correct an attribute error, you can
allow users to correct the error in the window, or you can include SCL statements
that make a correction in the labeled section for other fields.
If ERROR, ALWAYS, or ALLCMDS is also specified, then MAIN executes
after the window variable sections even if an error was introduced.
If the window contains an extended table, the window variable section for each
modified window variable executes for a row before the putrow section executes.
MAIN executes after the putrow section executes.
If CONTROL LABEL is specified, a window variable section must not contain a
SUBMIT IMMEDIATE block.
TERM | NOTERM
This option is valid only for FSEDIT applications. NOTERM is in effect by
default. Statements in the TERM section of FSEDIT applications do not execute
when a user scrolls off the current row in a SAS table unless the user changed the
values of one or more columns so that the current row needs to be updated in the
278
Chapter 13
•
SAS Component Language Dictionary
table, or unless the row is new. Use the TERM option to force execution of the
statements in the TERM section even if a user does not modify any columns in
the current row.
Details
The CONTROL statement controls the execution of labeled program sections and also
controls the formatting of code in a submit block. A CONTROL statement option
remains in effect until another CONTROL statement option overrides it. Multiple
CONTROL statement options can be in effect at the same time.
Examples
Example 1: Using the ASIS Option
Use the ASIS option:
control asis;
submit;
data a;
input x y z;
datalines;
10 20 30
40 50 60
run;
endsubmit;
rc=preview('display');
With the CONTROL ASIS statement in effect, the submit block executes without errors.
If you remove the CONTROL ASIS statement, SCL formats the code within the block as
follows when the code is submitted for processing:
data a;
input x y z;
datalines;
0 20 30 40 50 60 run;
When formatted in this manner, the final statement contains a syntax error and the code
cannot execute properly.
Example 2: Controlling a Program Interrupt
Define a break handler section labeled STOPINIT. When a user interrupts processing
while SCL statements in INIT are executing, the STOPINIT label executes. If the loop
index I is less than 350, execution of the program halts and control returns to the calling
program. Otherwise, execution resumes. After the first loop is finished, execute
CONTROL NOBREAK so that there is no break handler. If a user interrupts processing
during the second loop, the SCL Break window is displayed, and the statements in
STOPINIT do not execute. The user can either abort or resume processing. Follow the
same steps to define a new break handler section labeled STOPTERM in the TERM
section.
INIT:
/* define break label STOPINIT
control break stopinit;
/* loop 500 times to allow interrupt
/* checking with control break
/* if user interrupts, statements in
/* label STOPINIT execute */
*/
*/
*/
*/
CONTROL
do i=1 to 500;
put i=;
end;
/* reset so there is no break handler */
control nobreak;
/* loop 500 times to allow interrupt */
/* checking without control break
*/
do i = 1 to 500;
if (int(i/25) eq (i/25)) then put i=;
end;
return;
MAIN: return;
TERM:
/* Define the new break label STOPTERM. */
control break stopterm;
/* Loop 500 times to allow */
/* interrupt checking with control */
/* break. If user interrupts,
*/
/* statements in label STOPTERM
*/
/* execute.
*/
do j=1 to 500;
put j=;
end;
/* Reset so there is no break handler. */
control nobreak;
/* Loop 500 times to allow */
/* interrupt checking without control */
/* break.
*/
do j = 1 to 500;
if (int(j/25) eq (j/25)) then put j=;
end;
return;
STOPINIT:
/* HALT if loop counter is less than 350, */
/* otherwise RESUME.
*/
/* Report the current status.
*/
put i=;
if (i < 350) then
_status_ = 'H';
else
_status_ = 'R';
return;
STOPTERM:
/* HALT if loop counter is less than 350, */
/* otherwise RESUME.
*/
/* Report the current status.
*/
put j=;
if (j < 350) then
_status_ = 'H';
else
_status_ = 'R';
return;
See Also
“WORD” on page 734
279
280
Chapter 13
•
SAS Component Language Dictionary
COPY
Copies a SAS table, view, catalog, or catalog entry
Category:
Utility
Syntax
sysrc=COPY(old-name, new-name <,type>);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
old-name
is the name of the SAS file or catalog entry to copy. This can be a one-, two-, or
four-level name and can include SAS data set options.
Type: Character
new-name
is the new name for the SAS file or catalog entry. This must be a three- or four-level
name if type is 'CATALOG'. If a catalog entry is being copied, the function sets the
entry type of the new entry to that of the old entry. You can also specify SAS data set
options.
Type: Character
Optional Argument
type
is the type of SAS file or catalog entry to be copied:
'ACCESS'
The member is an access descriptor that was created using SAS/ACCESS
software.
'CATALOG'
The member is a SAS catalog or a catalog entry.
'DATA'
The member is a SAS data file. (This is the default.)
'MDDB'
The member is an MDDB.
'VIEW'
The member is a SAS data view.
Type: Character
COPY
281
Details
To copy a catalog entry, specify the complete four-level name of the entry for old-name,
a three-level name for new-name, and 'CATALOG' for type.
You can use the WHERE= data set option to copy only those rows that meet a WHERE
subset to the new table.
The COPY function does not copy existing integrity constraints to the new SAS table.
Use the ICCREATE function to define new integrity constraints.
If the SAS table that is being copied is indexed, then all indexes are rebuilt for the new
SAS table. New-name is ignored when you use COPY to copy GRSEG catalog entries
that were created using SAS/GRAPH software. A copied GRSEG entry will have either
the same name as the original entry or, if an entry with that name already exists in the
target catalog, a unique name generated by SAS software.
CAUTION:
This function can overwrite existing files. If a table or catalog with the specified
new name already exists, COPY overwrites the existing table or catalog without
warning.
Examples
Example 1: Copying Data Sets
Copy the SAS table DATA1 to DATA2 and copy WORK.TEMP.A.SCL to
SASUSER.PROFILE.B.SCL:
if (copy('data1','data2')) then
do;
_msg_=sysmsg();
...SCL statements to handle the
error condition...
end;
rc=copy('work.temp.a.scl',
'sasuser.profile.b.scl', 'catalog');
if (rc) then
do;
_msg_=sysmsg();
...SCL statements to handle the
error condition...
end;
Example 2: Copying Using a WHERE Clause
Copy from the SAS table SASUSER.CLASS to WORK.CLASS only those rows in
which the variable SEX=M:
if (copy('sasuser.class(where=(SEX=”M”))',
'work.class')) then
do;
_msg_=sysmsg();
...SCL statements to handle the
error condition...
end;
282
Chapter 13
•
SAS Component Language Dictionary
Example 3: Copying a Password-protected Data Set
rc=copy('sasuser.class(pw=myPassword)',
'sasuser.class2(pw=myPassword2)');
See Also
•
“DELETE” on page 308
•
“ICCREATE” on page 444
•
“RENAME” on page 615
COPYARRAY
Copies data from one array into another array
Category:
Array
Syntax
rc=COPYARRAY(source_array,target_array<,ignoresize> );
Required Arguments
rc
indicates whether the operation was successful.
0
successful
≠0
not successful
Type: Numeric
source_array
is the array to copy the values from.
Type: Array
target_array
is the array to copy the values into.
Type: Array
Optional Argument
ignoresize
indicates whether to check for array sizes to be the same.
'Y'
tells SCL to ignore array sizes.
'N'
tells SCL to check whether the source and target arrays are the same size.
(This value is the default.)
Type: Character
COPYARRAY 283
Details
The COPYARRAY function allows you to copy data from one array (source_array) into
another array (target_array). The arrays must have the same dimensions and size and be
of the same type. The source array being copied from can be a static or dynamic array,
but if it is a dynamic array then its size must already have been set using MAKEARRAY
or REDIM. The target array being copied into can also be a static or dynamic array. If it
is dynamic and has not yet been created, then COPYARRAY will create the array to the
same size of the source array. However, the low bound of a dynamic array is always 1,
so the resultant target array may end up with different low or high bounds in each of its
dimensions.
If you set ignoresize to 'Y', then the sizes of the arrays do not have to match. Only the
types and dimensions of the arrays have to match. In this case, if the source array is
bigger than the target array, then the elements in the source array will be truncated, and
you will lose the data in the elements that do not coincide. If the source array is smaller
than the target array, then the elements in target array that are not set will be
automatically set to missing values.
If the COPYARRAY is used to create a dynamic array, the DELARRAY function
should be used to delete the dynamic array.
Examples
Example 1: Copy Elements of a One–Dimensional Array
The example copies the elements of the one–dimensional array A into the one–
dimensional array B and prints out the contents of the arrays.
DCL num a(5) b(5);
do i=1 to 5;
a[i] = i;
end;
rc = copyarray(a,b);
put a=; put b=;
The result of this code would be:
a=
a[1]
a[2]
a[3]
a[4]
a[5]
b=
b[1]
b[2]
b[3]
b[4]
b[5]
=
=
=
=
=
1
2
3
4
5
=
=
=
=
=
1
2
3
4
5
Example 2: Copy Elements of a Two–Dimensional Array
The example copies the elements of the two–dimensional array A into the two–
dimensional array B and prints out the contents of the arrays.
DCL num a(2,2) b(3,4);
count=0;
do i=1 to 2;
284
Chapter 13
•
SAS Component Language Dictionary
do j=1 to 2;
count+1;
a[i,j] = count;
end;
end;
rc = copyarray(a,b,'y');
put a=; put b=;
The result of this code would be:
a=
a[1,1]
a[1,2]
a[2,1]
a[2,2]
b=
b[1,1]
b[1,2]
b[1,3]
b[1,4]
b[2,1]
b[2,2]
b[2,3]
b[2,4]
b[3,1]
b[3,2]
b[3,3]
b[3,4]
=
=
=
=
1
2
3
4
=
=
=
=
=
=
=
=
=
=
=
=
1
2
.
.
3
4
.
.
.
.
.
.
See Also
•
“DELARRAY” on page 307
•
“MAKEARRAY” on page 525
•
“REDIM” on page 610
•
“Introduction to SCL Arrays” on page 41
COPYLIST
Copies or merges the contents of an SCL list into an existing list or a new list
Category:
List
Syntax
new-list-id=COPYLIST(list-id<,options><,target-list-id>);
Required Arguments
new-list-id
is either the identifier of the new list to contain a copy of the contents of list-id, if
target-list-id is not supplied, or target-list-id, if a target list is supplied.
Type: Numeric
COPYLIST
285
list-id
is the identifier of the list to copy or merge into the target list. An invalid list-id
produces an error condition.
Type: Numeric or List
Optional Arguments
options
specify whether list values are merged and control how sublists are copied or
merged. You can use one or more of the following values, separated by spaces. Later
keywords override previous keywords.
'NONRECURSIVELY'|'NO'|'N'
copies or merges only sublist identifiers as values for sublist items. (This is the
default.)
'MERGE'|'M'
merges the contents of the source list-id into the target-list-id, replacing likenamed existing items in the target list. You may combine this option with the
recursive option. An error occurs if target-list-id is not supplied or is not a valid
list identifier.
'RECURSIVELY'|'YES'|'Y'
copies or merges all items of sublists and of sublists of sublists, and so on.
Type: Character
target-list-id
is the identifier of the list into which the source list is copied or merged. If supplied,
target-list-id is also returned. Otherwise, a new list is created and returned. New
sublists are created with the same environment (local or global) as the target list.
An error condition results if the target list has attributes such as NOUPDATE and
FIXEDLENGTH that prevent copying data into it.
Type: Numeric
Details
The copy operation appends items from the source list to the end of the target list,
whereas the merge operation copies them into the target list, replacing existing named
items.
If an SCL object is passed to COPYLIST as list-id, the resulting copy is not an SCL
object. Although the new list contains all items from the original object, methods can not
be called on this copy. The copied list is also treated as a regular list for comparisons
(e.g., COMPARELIST).
If target-list-id is omitted, the function creates a new list in the same environment (L or
G) as the list being copied and makes the new list the target-list-id. (For a description of
list environments, see “ENVLIST” on page 350.) If target-list-id is supplied, its
identifier is returned in new-list-id.
When a list is copied recursively, the items in all sublists are also copied, not just the
sublist identifiers. However, even this duplication is avoided if it would result in an
infinite recursion. When copying a list recursively, SCL does not perform an infinite
recursive copy. For example, if a list contains itself, COPYLIST detects the circular
structure and recreates the structure in the copy.
Merging occurs by item names. All items in the source list (and in its sublists, if merging
is recursive) must have names. For each item, the name is used to find a matching name
286
Chapter 13
•
SAS Component Language Dictionary
in the target list, as with NAMEDITEM(list-id name). If the same name appears multiple
times in the source list, each item is merged independently. That is, the last occurrence
of the name overwrites previous merged values and does not match with subsequent
items in the target list. Thus, you should strive to keep item names unique in the source
list in order to avoid wasted processing. If the corresponding item is not found in the
target list, a new item is created.
In the merge operation, a list or sublist is merged only once, even if it appears multiple
times. Also, a warning is printed for items that do not have names.
If an item in the source list has the NOWRITE attribute, then the corresponding item in
the target list is deleted, unless it has the NODELETE attribute, in which case it is not
merged. If a scalar item replaces a sublist item in a merge, the replaced list is not deleted
because it may be used elsewhere. The SCL program must explicitly delete the old list.
All attributes of the list and its contents are preserved when a list is copied. The
password is not copied so that you can modify the copy without knowing the password
of the original list. The copy has no password. (See “SETLATTR” on page 662 for a
discussion of passwords for lists.)
COPYLIST ignores any invalid options and uses its defaults instead.
Examples
Example 1: Copying a Single List
/* make B a local named list */
/* with 2 items named x, y
*/
b=makenlist('L','x','y');
b=setnitemc(b,'ABC','x');
b=setnitemc(b,'XYZ','y');
/* make A a local named list
*/
/* with 3 items named A, B, and C */
a=makenlist('L','A','B','C');
a=setnitemn(a,3.5,'A');
a=setniteml(a,b,'B');
a=setnitemn(a,9.75,'C');
call putlist(a,'A=',2);
NREC=copylist(a,'N');
/* nonrecursive copy */
call putlist(NREC,'NREC=',2);
REC=copylist(a,'Y');
/* recursive copy */
call putlist(REC,'REC=',2);
This program produces the following output:
A=(
A=3.5
B=( x='ABC'
y='XYZ'
)[3]
C=9.75
)[5]
NREC=( A=3.5
B=( x='ABC'
y='XYZ'
)[3]
C=9.75
COPYLIST
287
)[7]
A=3.5
B=( x='ABC'
y='XYZ'
)[11]
C=9.75
)[9]
REC=(
The sublist named B in the outer list NREC is the same list as the sublist named B in the
outer list named A, from which NREC was copied non-recursively. Both lists named B
have the same list identifier (3), which means they are in fact the same list. However, the
sublist named B in the outer list REC, which was copied recursively from list A, is a
different list, although it has the same contents as the list named B from A. The sublist in
the outer list REC has a list identifier of 11, not 3, which shows it is a different list.
Note: [5], [7], and [9] are the list identifiers that were assigned when this example was
run and may be different each time the example is run.
Example 2: Appending a List to Itself
Append the list MYLIST to itself. Both NEWLIST and MYLIST contain the list
identifier for the copy of MYLIST.
mylist=makelist();
mylist=insertn(mylist,1,-1);
mylist=insertn(mylist,2,-1);
mylist=insertn(mylist,3,-1);
newlist = copylist(mylist,'N',mylist);
NEWLIST contains the values 1, 2, 3, 1, 2, 3.
Example 3: Merging One List into Another List
INIT:
a = makenlist('L','A','B','C','D','E','F');
do i = 1 to listlen(a);
a = setitemc(a, nameitem(a,i),i);
end;
c = insertc(makelist(),'?',-1,'NOT');
a = insertl(a, c,-1,'WHY');
b = makenlist('L','A','E','I','O','U');
do i = 1 to listlen(b);
b = setitemn(b, rank(nameitem(b,i)),i);
end;
b =
insertl(b, insertn(makelist(),0,-1,'NOT'),-1,
'WHY');
call putlist(a,'A before merge:');
call putlist(b,'B before merge:');
b = copylist(a,'yes merge',b);
call putlist(b,'B after merge :');
return;
The result is
A before merge:(A='A' B='B' C='C' D='D' E='E'
F='F'
WHY=(NOT='?' )[7] )[5]
B before merge:(A=65 E=69 I=73 O=79 U=85
288
Chapter 13
•
SAS Component Language Dictionary
WHY=(NOT=0 )[11] )[9]
B after merge :(A='A' E='E' I=73 O=79 U=85
WHY=(NOT='?' )[11] B='B' C='C'
D='D' F='F' )[9]
The result list B contains items from A where the names intersect as well as original
items from B for items that were not found in A. Because the sublist WHY was found in
both, a recursive merge replaced 0 from the sublist of B with '?' from the sublist of A.
Note: 7, 5, 11, and 9 are the list identifiers that were assigned when this example was
run and may be different each time the example is run.
Example 4: Copying Multiple Instances of a List
Copy a list, which contains a copy of itself, non-recursively and recursively. The outer
list R1 contains two items, named SELF and R1, which are actually the same list as R1.
When a non-recursive copy, R2, is made, the copy has items named SELF and R1 which
are still the list R1. Only when R1 is copied recursively as R3 does the copy contain
itself instead of R1.
/*
Create the list L, fill it, and print R1. */
r1=makenlist('l','a','SELF','r1', 'x');
r1=setniteml(r1,r1,'SELF'));
r1=setniteml(r1,r1,'r1'));
r1=setnitemn(r1,1,'a'));
r1=setnitemn(r1,99,'x'));
call putlist(r1,'R1=',2));
/* Copy R1 nonrecursively into R2 and print R2 */
r2=copylist(r1,'n');
call putlist(r2,'R2=',2);
/* Copy R1 recursively into R3 and print R3 */
r3=copylist(r1,'y');
call putlist(r3,'R3=',2);
The list R2, which was created with a nonrecursive copy operation, contains the list R1.
Note that the structure of the list R3 is identical to that of R1: it contains two copies of
itself, at items named SELF and R1, because these items are lists whose list identifier is
the same as the list R3.
This program produces the following output:
R1=(
a=1
SELF=(...)[13]
R1=(...)[13]
x=99
)[13]
R2=( a=1
SELF=( a=1
SELF=(...)[13]
R1=(...)[13]
x=99
)[13]
R1=(...)[13]
x=99
)[15]
R3=( a=1
SELF=(...)[17]
R1=(...)[17]
x=99
CREATESCL
289
)[17]
Note: 13, 15, and 17 are the list identifiers that were assigned when this example was
run and may be different each time the example is run.
Example 5: Merging Nonrecursively and Recursively
Merge the contents of the list identified in SOURCEID into the list identified in
TARGETID. The second call does a recursive merge.
targetid=copylist(sourceid,"MERGE",targetid);
targetid=copylist(sourceid,"MERGE YES",targetid);
See Also
•
“DELLIST” on page 311
•
“GETLATTR” on page 426
•
“HASATTR” on page 442
•
“MAKELIST” on page 527
•
“MAKENLIST” on page 528
•
“PUTLIST” on page 607
•
“SETLATTR” on page 662
CREATESCL
Writes class or interface information to an SCL entry
Category:
Object Oriented
Syntax
entry-id=CREATESCL(entry-name, scl-entry<,description> <,proxy> );
Required Arguments
entry-id
contains the identifier that is assigned to the class, interface, or class package. If the
class does not exist, entry-id contains 0.
Type: Numeric
entry-name
is the one- to four-level name of the CLASS, INTERFACE, or CLASSPKG catalog
entry to load. If entry-name is a one- or two-level name, then the current search path
is used to find the CLASS, INTERFACE, or CLASSPKG entry. If the entry was
previously loaded, then the same identifier is returned. Otherwise, the entry is loaded
from the catalog into the application class list, and the entry identifier is returned in
entry-id.
Type: Character
scl-entry
is the one- to four-level name of the SCL entry to be created. If proxy is 1 and entryname is a CLASSPKG entry, then you can specify a two-level name for scl-entry,
290
Chapter 13
•
SAS Component Language Dictionary
and CREATESCL will generate a series of proxy entries for the classes in the class
package.
Type: Character
Optional Arguments
description
is the description of the SCL entry.
Type: Character
proxy
specifies whether CREATSCL should generate proxy entries. The default value of 0
means that CREATESCL will not generate proxy entries.
Specify 1 if you want CREATESCL to generate proxies. If entry-name is a CLASS
or an INTRFACE entry, then CREATESCL will generate a proxy entry for the class
or interface. If entry-name is a CLASSPKG entry, and scl-entry is a two-level name,
then CREATESCL will generate a proxy entry for each of the classes in the package
(each class specified in an ITEM statement).
Type: Numeric
Details
CREATESCL writes the class or interface definition that is in entry-name to an SCL
entry. The class definition is written to a CLASS or INTERFACE statement block in the
SCL entry that is specified in scl-entry.
You can revise the code in scl-entry and use the SAVECLASS command to create a new
or revised class/interface. For example, you can use the CREATESCL function to
generate an SCOM class that contains Version 6 class information. You can add the
method signatures, scope, and so on, and then generate a new class using the
SAVECLASS command. This process is described in “Converting Version 6 NonVisual Classes to SCOM Classes” on page 145.
For a description of the CLASS and INTERFACE statement syntax that is written to the
SCL entry, see “CLASS” on page 249 and “INTERFACE” on page 475.
Examples
Example 1: Generate CLASS SCL Entry
Generate the SCL code for SASHELP.CLASSES.CHECKBOX_C.CLASS. Store the
SCL code in WORK.A.CHECKBOX_C.SCL:
myClass=CREATESCL('sashelp.classes.checkbox_c.class',
'work.a.checkbox_c.scl',
'CheckBox class to convert');
Example 2: Generate CLASSPKG SCL Entry
Generate the SCL code for SASHELP.IOMSAMP.TSTPKG.CLASSPKG. Store the
SCL code in WORK.A.B.SCL:
rc = createscl('sashelp.iomsamp.tstpkg.classpkg','work.a.b.scl');
Example 3: Generate A Proxy Entry
Generate a proxy entry for SASHELP.CLASSES.SCLLIST.CLASS.
_CURCOL_
291
rc = createscl('sashelp.classes.scllist.class','work.a.c.scl','',1);
The CLASS statement needed to generate the proxy class is stored in WORK.A.C.SCL.
If you issue the SAVECLASS command for WORK.A.C.SCL, then SCL will generate
the associated proxy class SCLLISTPROXY.CLASS.
Note: CREATESCL will generate native='/sasprxy:0' for each of the methods
defined in the class. Do not modify this method option.
Example 4: Generate A Series of Proxy Entries
Generate an SCL proxy file for each of the classes specified in
SASHELP.IOMSAMP.TSTPKG.CLASSPKG. This class package contains a ITEM
statement for these classes:
•
SASHELP.IOMSAMP.AFTESTTYPES.CLASS
•
SASHELP.CLASSES.SCLLIST.CLASS
rc = createscl('sashelp.iomsamp.tstpkg.classpkg','work.a','',1);
This statement creates two SCL entries in the WORK.A catalog:
AFTESTTYPESPROXY.SCL and SCLLISTPROXY.SCL. These SCL entries contain
the CLASS statements needed to generate the proxy classes. If you issue the
SAVECLASS command for these SCL entries, SCL will generate the proxy CLASS
files.
Note: CREATESCL will generate native='/sasprxy:0' for each of the methods
defined in the class. Do not modify this method option.
See Also
•
“APPLY” on page 219
•
“INSTANCE” on page 474
•
“LOADRES” on page 518
•
“NOTIFY” on page 569
•
“SEND” on page 649
•
“SUPAPPLY” on page 686
•
“SUPER” on page 688
_CURCOL_
Contains the value of the leftmost column in an extended table control in a FRAME entry
Category:
System Variable
Details
_CURCOL_ is a system variable. It is provided automatically by the FRAME entry in
SAS/AF, and the SCL compiler automatically creates a space for it in the SCL data
vector.
292
Chapter 13
•
SAS Component Language Dictionary
The value of _CURCOL_ is updated when the getrow or putrow section or the _getrow
or _putrow method of an extended table is executing. Therefore, _CURCOL_ must be
referenced only within these sections.
_CURCOL_ is available only in SAS/AF FRAME entries.
Example
Suppose you have a text entry control, TEXT, in an extended table control. TEXT is
assigned a value in the getrow section, based on a substring of a longer string. When the
extended table is scrolled left and right, the value of _CURCOL_ is updated and is used
as the position argument to the SUBSTR function.
GET1:
text = substr( longstring, _curcol_ );
return;
For more information about extended table controls for horizontal scrolling, see the
documentation for SAS/AF classes.
See Also
“_CURROW_” on page 296
CURFLD
Returns the name of the FRAME or PROGRAM entry control or field on which the cursor is currently
positioned
Category:
Cursor
Syntax
wvar-name=CURFLD();
Required Argument
wvar-name
contains the name of the FRAME or PROGRAM entry control or field on which the
cursor is currently positioned.
Type: Character
Details
The CURFLD function returns the name of the field FRAME or PROGRAM entry
control on which the cursor is located. If the cursor is not positioned on a window
variable, a null string is returned. CURFLD is usually used in conjunction with a
CONTROL statement that includes the ENTER, ALWAYS, or ALLCMDS option. You
can use CONTROL LABEL to achieve the same result more efficiently. FRAME or
PROGRAM entries can also use the _getCurrentName method.
Example
Use CURFLD to control the behavior of an SCL entry application:
CURLIST
293
INIT:
control enter;
return;
MAIN:
select( curfld() );
when('PHONE') call display('phone.help');
when('EMPLOYEE') call display
('employee.scl');
otherwise;
end;
return;
This example can be implemented without CURFLD if the program contains a program
block that is labeled with the name of the window variable. If the program is in a SCL
entry, then the window variables must be of type PUSHBTNC or PUSHBTNN, and the
INIT section must contain CONTROL LABEL.
INIT:
controllable;
return;
PHONE:
call display('phone.help');
return;
EMPLOYEE:
call display('employee.scl');
return;
See Also
•
“CONTROL” on page 274
•
“CURSOR” on page 296
•
“CURWORD” on page 298
CURLIST
Designates or reports the current result SCL list
Category:
List
Syntax
list-id=CURLIST(<new-list-id>);
Required Argument
list-id
is the identifier of the list to receive the values returned by the next SCL selection list
function that is invoked.
>0
is the list identifier of the SCL list that was previously defined as current
with the CURLIST function.
0
indicates that no list is defined as the current list.
Type: Numeric or List
294
Chapter 13
•
SAS Component Language Dictionary
Optional Argument
new-list-id
is the identifier of the list to be designated as the current list. An invalid new-list-id
produces an error condition.
Type: Numeric
Details
When a value is provided for new-list-id, CURLIST designates the SCL list that is
identified by new-list-id as the current result list. New-list-id must be the list identifier
that was returned by the MAKELIST, MAKENLIST, or COPYLIST function that
created this list. If you omit new-list-id, then CURLIST returns the identifier of the SCL
list that was already designated as the current result list by CURLIST. If no argument is
passed to CURLIST and no current result list has been specified, CURLIST returns 0.
The current result list is filled automatically with the values that are selected when the
next SCL selection list function executes.
The functions that can fill the current result list are the SCL selection list functions
CATLIST, COLORLIST, DATALISTC, DATALISTN, DEVLIST, DIRLIST,
FILELIST, LIBLIST, LISTC, LISTN, LVARLEVEL, and VARLIST. For example,
CATLIST opens a selection list window that displays the names of catalog entries. The
value returned by CATLIST is a character string containing each catalog name that users
select, separated by blanks. Selection list functions like CATLIST can also automatically
fill the current result list, as specified by CURLIST, with a character item for each
selection that users make. The length of that list is unbounded.
When one of the selection list functions is invoked, the values that users select replace
the entire contents of the current result list. To preserve the contents of the current result
list, use COPYLIST to copy the list before calling another selection list function.
Example
Set up a selection list, invoke a selection list function, and access the selections:
clist=makelist();
oldcurlist=curlist(clist);
/* Allow user to choose up to 16 graphs. */
graphs=catlist('SASUSER.DEMO','GRSEG',16,'Y');
n=getnitemn(clist,'COUNT');
do g=1 to n;
graphName=getnitemc(clist,'name',g);
put 'Selection #' g ' is ' graphName;
end;
/* Delete temporary curlist and restore +/
/* previous curlist. */
rc=dellist(clist);
oldcurlist=curlist(oldcurlist);
See Also
•
“CATLIST” on page 240
•
“COLORLIST” on page 265
•
“COPYLIST” on page 284
CUROBS
•
“DATALISTC and DATALISTN” on page 299
•
“DELLIST” on page 311
•
“DEVLIST” on page 318
•
“DIRLIST” on page 323
•
“FILELIST” on page 381
•
“LIBLIST” on page 504
•
“LISTC and LISTN” on page 509
•
“LVARLEVEL” on page 524
•
“MAKELIST” on page 527
•
“MAKENLIST” on page 528
•
“PUTLIST” on page 607
•
“VARLIST” on page 717
295
CUROBS
Returns the number of the current row in a SAS table
Category:
SAS Table
Syntax
row-number=CUROBS(table-id);
Required Arguments
row-number
is the current row number.
Type: Numeric
table-id
is the table identifier that was assigned when the table was opened. If table-id is
invalid, the program halts.
Type: Numeric
Details
CAUTION:
This function should be used only with an uncompressed SAS table that is
accessed using a native library engine.
If the engine that is being used does not support row numbers, the function returns a
missing value.
In FSEDIT and FSVIEW applications, specifying a value for table-id is optional. If the
argument is not specified, CUROBS returns the value for the SAS table displayed by
FSEDIT or FSVIEW. For a SAS table view, the function returns the relative row
number. Also, on engines that do not support absolute row numbers, such as ORACLE,
CUROBS returns the relative row number.
296
Chapter 13
•
SAS Component Language Dictionary
Examples
Example 1: Getting the Row Number of a Control
Use FETCHOBS to fetch the tenth row in the SAS table MYDATA. CUROBS returns a
value of 10 for row-number.
tableid=open('mydata','i');
rc=fetchobs(tableid,10);
rownum=curobs(tableid);
Example 2: Getting the Current Row Number
In an FSEDIT SCL program, retrieve the number of the row that is currently displayed:
rownum=curobs();
_CURROW_
Contains the number of the current row in an extended table
Category:
System Variable
Details
_CURROW_ is a system variable that is created for every SCL program that you
compile. The compiler creates a space for _CURROW_ in the SCL data vector.
_CURROW_ is updated when the getrow or putrow section of an extended table is
executing or when the _getrow or _putrow method of an extended table control is
executing. Therefore, _CURROW_ must be referenced only within these sections of an
SCL program.
_CURROW_ is available in PROGRAM and FRAME entries.
Example: Example
The following getrow section of a FRAME entry fetches a row from a previously opened
SAS table, using _CURROW_ as the row number.
GET1:
if fetchobs( tableid, _currow_ ) ne 0 then
call notify('table','endtable');
return;
See Also
•
“_CURCOL_” on page 291
•
“SETROW” on page 671
CURSOR
Positions the cursor in a specified widget or field of a FRAME entry
Category:
Widget or Field
CURTOP 297
Syntax
CURSOR wvar-name;
Required Argument
wvar-name
specifies which FRAME entry widget or field to position the cursor on.
Type: Character
Details
The CURSOR statement does not move the cursor immediately while the SCL program
is executing. Rather, it specifies where the cursor will be positioned when SCL returns
control to the procedure after the frame is updated. If multiple cursor statements execute,
the cursor is positioned on the FRAME entry widget or field that was specified in the
last CURSOR statement. In SAS/AF applications, a REFRESH statement also positions
the cursor, based on the last cursor statement.
The FRAME entry widget or field cannot be an element of an array. For an array
element, use the FIELD function instead.
FRAME entry widgets can also use the _cursor method.
Example
Move the cursor to ADDRESS if NAME is filled in:
if modified (name) and name ne '' then
cursor address;
See Also
•
“CURFLD” on page 292
•
“CURWORD” on page 298
•
“DISPLAYED” on page 329
•
“ERROR” on page 352
•
“ERROROFF” on page 353
•
“ERRORON” on page 354
•
“FIELD” on page 373
•
“HOME” on page 444
•
“MODIFIED” on page 545
•
“PROTECT” on page 602
•
“UNPROTECT” on page 703
CURTOP
Returns the number of the row that is currently displayed at the top of an extended table
298
Chapter 13
Category:
•
SAS Component Language Dictionary
Extended Table
Syntax
row=CURTOP();
Required Argument
row
is the number of the row that is currently displayed at the top of an extended table.
Type: Numeric
Details
CURTOP can be used only on extended tables in PROGRAM entries. Because extended
tables can be defined only in SAS/AF software, this function cannot be used in FSEDIT
or FSVIEW programs.
Example
Store the number of the table's top row in the column TOPROW:
toprow=curtop();
See Also
•
“ENDTABLE” on page 345
•
“SETROW” on page 671
•
“TOPROW” on page 696
CURWORD
Returns the word that is at the cursor position
Category:
Widget or Field
Syntax
word=CURWORD();
Required Argument
word
is the text of the word.
Type: Character
Details
CURWORD returns the word on which the text cursor was located when the user last
pressed ENTER. The retrieved character string begins with the first character of the
word on which the cursor was positioned and extends to the first space after the word.
DATALISTC and DATALISTN 299
CURWORD is usually used in conjunction with a CONTROL statement that includes
the ENTER, ALWAYS, or ALLCMDS option.
If CURWORD is used on a window variable that has been modified, the field value is
justified before CURWORD executes.
Example
Suppose a PROGRAM entry window contains text entry widgets that contain the words
PROJECT1 and PROJECT2. The entry's program determines which action to perform by
determining which word the cursor is positioned on when the user presses ENTER.
INIT:
widget enter;
return;
MAIN:
word=curword();
if (word='PROJECT1') then
submit continue;
proc print data=project1;
run;
endsubmit;
else if (word='PROJECT2') then
submit continue;
proc print data=project2;
run;
endsubmit;
else _msg_=
'Please position the cursor on a valid selection.';
return;
TERM:
return;
See Also
•
“CONTROL” on page 274
•
“CURFLD” on page 292
•
“CURSOR” on page 296
•
“LOOKUPC” on page 522
DATALISTC and DATALISTN
Displays a selection list window that contains the values of particular columns from rows in a SAS table
and returns user selections
Category:
SAS Table
Syntax
selection=DATALISTC(table-id,
col-list<,message<,autoclose<,num-sel<, label> > > > );
300
Chapter 13
•
SAS Component Language Dictionary
selection=DATALISTN(table-id,
col-list<,message<,autoclose<,num-sel<, label> > > > );
Required Arguments
selection
is the value of the first column from the selected row. For DATALISTC, the value is
the first character column. For DATALISTN, the value is the first numeric column.
Selection is a missing value (period) if the user closes the selection list window
without making a selection.
For DATALISTC, selection is blank if the selection list window is closed and no
selections are made. By default, selection is 200 bytes long. To accommodate a value
longer than 200 bytes, explicitly declare selection with a longer length.
Type: Character, Numeric.
table-id
is the identifier that was assigned when the table was opened. If table-id is invalid,
the program halts.
Type: Numeric
col-list
is a list of column names, separated by blanks, from the SAS table to be displayed.
For DATALISTC, the first column in this list must be character or else the program
halts. For DATALISTN, the first column must be numeric or else the program halts.
However, the remaining columns in the list can be of any type.
Type: Character
Optional Arguments
message
is the text for a message to be displayed above the selection list. The default message
tells users to make up to the number of selections specified in num-sel.
Type: Character
autoclose
specifies whether the selection list window closes automatically after a user makes a
selection when only one choice is allowed:
'Y'
closes the window automatically. (This is the default.)
'N'
leaves the window open until the user explicitly closes it.
This option is ignored when num-sel is not 1. However, use '' as a placeholder if
you are also specifying a value for num-sel.
Type: Character
num-sel
specifies the maximum number of items a user can select from the list. To display
the list for information purposes only (no selections allowed), specify 0. To specify
unlimited selections, use a value that is larger than the number of available
selections, such as 9999.
Type: Numeric
DATALISTC and DATALISTN 301
label
specifies whether the selection list window displays the column label text for each
column.
'N'
does not display the labels. (This is the default.)
'Y'
displays column names as column label text.
Type: Character
Details
If a user ends the selection list window without making a selection, DATALISTC and
DATALISTN return a blank value. If the user exits by using OK without making a
selection, then the selection variable is set to blank. However, if the user exits using
CANCEL without making a selection, the selection variable retains any previous value
it may have had.
Although a user can position the cursor or mouse pointer anywhere in a row to make a
selection from the list, only the value of the first column is returned. (The other column
values are displayed for information only.)
When multiple selections are allowed, selection contains only the value of the first
column in the last selected row. However, values for displayed columns for all rows that
are selected can be returned in the current result list if one is available. The current result
list is a special SCL list that is automatically filled with the values selected from a
selection list. To create a current result list, use the MAKELIST function to create it, and
use the CURLIST function to designate it as the current result list. The current result list
must exist before you call the DATALISTC or DATALISTN function.
By default, a message is displayed asking the user to make one selection, and the
selection list window closes automatically when the user makes a selection.
When DATALISTC or DATALISTN is invoked, the current result list is cleared. After
DATALISTC or DATALISTN is invoked, the result list contains the following named
items:
TAG
identifies the list as one that was created by the DATALISTC function.
Type: Character
COUNT
contains either the number of selected elements, or 0 if a user makes no selections or
issues a CANCEL command in the list window.
Type: Numeric
var-name
contains the value of column var-name in var-list for each selection.
Type: Numeric or Character
Examples
Example 1: Using DATALISTC to Return a Single Selection
Create a selection list whose rows contain the values of the columns NAME, STREET,
CITY, STATE, and ZIP from the SAS table identified by the SCL variable CLASSID,
which was returned by the OPEN function. NAME contains the value for the selected
row. The other columns are displayed for information purposes only.
302
Chapter 13
•
SAS Component Language Dictionary
name=datalistc(classid,'name street city state zip');
Example 2: Using DATALISTN to Return Multiple Selections
Create a selection list whose rows contain the values of the columns ITEMNUM,
ITEMAMT, CUSTNAM, and CUSTADR from the SAS table identified by the SCL
variable SALESID. Allow users to make up to three selections from this selection list.
Then retrieve the values for each column for each of the selected rows from the current
result list.
salesid=open('sales');
listid=makelist();
rc=curlist(listid);
itemnum=datalistn(salesid,
'itemnum itemamt custnam custadr','','',3);
n=getnitemn(listid,'COUNT');
do i=1 to n;
itemnum=getnitemn(listid,'ITEMNUM',i);
itemamt=getnitemn(listid,'ITEMAMT',i);
custnam=getnitemc(listid,'CUSTNAM',i);
custadr=getnitemc(listid,'CUSTADR',i);
put itemnum= itemamt= custnam= custadr=;
end;
rc=close(salesid);
See Also
•
“LISTC and LISTN” on page 509
•
“LOCATEC and LOCATEN” on page 519
•
“SHOWLIST” on page 673
•
“VARLIST” on page 717
DCLOSE
Closes a directory
Category:
Directory
Syntax
sysrc=DCLOSE(directory-id);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
DCREATE
303
directory-id
is the identifier that was assigned when the directory was opened. If directory-id is
invalid, the program halts.
Type: Numeric
Details
The DCLOSE function closes a directory that was previously opened by the DOPEN
function. DCLOSE also closes any open members of the directory before closing the
directory.
Example
Open the directory to which the fileref MYDIR has previously been assigned, return the
number of members, and then close the directory:
rc=filename('mydir','fname')
did=dopen('mydir');
memcount=dnum(did);
if (dclose(did)) then
do;
_msg_=sysmsg();
...SCL statements to handle the error condition...
end;
See Also
•
“DOPEN” on page 333
•
“FCLOSE” on page 365
•
“FOPEN” on page 401
•
“MOPEN” on page 548
DCREATE
Creates an external directory
Category:
External File
Syntax
new-directory=DCREATE(dir-name<,parent-dir> );
Required Arguments
new-directory
contains the complete pathname of the new directory, or an empty string if the
directory cannot be created.
Type: Character
dir-name
is the name of the directory to create. This must be only the directory name and
cannot include a pathname.
304
Chapter 13
•
SAS Component Language Dictionary
Type: Character
Optional Argument
parent-dir
is the complete pathname of the directory in which to create the new directory. If
parent-dir is not supplied, then the current directory is the parent directory.
Type: Character
Details
DCREATE enables you to create a directory in your operating environment.
Operating Environment Information
On CMS, DCREATE works only for shared file system (SFS) directories.
Example
•
Create a new directory on UNIX, using the name stored in the variable DIRNAME:
newdir=dcreate(dirname,'/local/u/abcdef/');
•
Create a directory on Windows, using the name stored in the variable DIRNAME:
newdir=dcreate(dirname,'d:\testdir\');
•
Create a new directory on CMS, using the name stored in the variable DIRNAME:
newdir=dcreate(dirname,'auser.');
DECLARE
Declares variables and specifies their data types
Category:
Alias:
Declarative Statement
DCL
Syntax
DECLARE|DCL data-type-1 argument-1 < . . . ,data-type-n argument-n > ;
Required Arguments
data-type
specifies the data types to assign. Multiple data types may be declared with one
DECLARE statement. Use a comma to separate multiple data types. If you omit a
comma between data types, then subsequent data type names are interpreted as
variable names until the next comma is encountered.
The following are valid data types:
'CHAR <(n)>'
is for variables that can contain character values. Optionally, n is the length in
characters. The default length is 200, while the maximum is 32,767. Declaring a
length for CHAR variables that will store values shorter than 200 characters can
DECLARE
305
reduce the amount of memory required to store a program's variables. The
STRING data type is an alias of the CHAR data type.
'LIST'
is for variables that can reference an SCL list.
'NUM'
is for variables that can contain numeric values.
'OBJECT'
is for variables that can contain the identifier of a component.
Note: The compiler cannot validate attributes or methods for objects declared
with the OBJECT keyword (generic objects). Consequently, using generic
objects is less efficient (possibly up to 25 percent less efficient) than
declaring objects with the CLASS or INTERFACE keyword. See “Objects”
on page 22 for more information.
class-name
is for variables that can contain the identifier of an instance of a particular class.
It can be a one– to four–level name.
Type: Character
argument-1 < . . . argument-n>
can be one or more constants and/or one or more variable names. The constants
and/or variable names should be separated by spaces. When initializing lists, you can
use either braces ({ and }) or brackets ([ and]) to enclose a series of list items.
Variable names can be any of the following:
variable
variable = initial-value
variable = expression
variable-1 – variable-n = (value-1,...,value-n)
listname1={value-1,...,value-n}
listname2=[value-1,...,value-n]
Constants have the following form:
•
constant-n<=value-n>
Type: Character or Numeric (for variables).
Type: Character (for constants).
Details
The DECLARE statement declares a variable of any SCL data type. DECLARE can be
used within a DO, SELECT, or USECLASS block to define variables that are available
only within that block. This enables you to enforce variable scoping, because variables
that you declare within a DO, SELECT, or USECLASS block are local to that block.
You can use the DECLARE statement to declare any type of array. However, arrays that
are declared with the DECLARE statement are all temporary arrays. See “Using
Temporary Arrays to Conserve Memory in SCL Programs” on page 51.
Although you can use the LENGTH statement to declare numeric and character
variables, you might want to use the DECLARE statement in order to enforce variable
scoping.
306
Chapter 13
•
SAS Component Language Dictionary
Place DECLARE statements either before the first labeled section of an SCL program or
inside a DO or SELECT block.
You can use either braces ({ and }) or brackets ([ or ]) to enclose a series of list items
when you initialize an SCL list. For example, both of the following list definitions are
valid:
dcl list x = {1,2,3};
dcl list z = [4,5,6];
Comparisons
•
You can use the DECLARE statement to declare any SCL data type, whereas the
LENGTH statement can declare only numeric and character variables.
•
You can use the DECLARE statement inside a DO block, whereas the LENGTH
statement cannot be used inside a DO block.
•
You can use the DECLARE statement to declare temporary arrays, but you must use
the ARRAY statement to declare indirect or non-temporary arrays.
For details about the LENGTH statement in the Base SAS language, see SAS
Statements: Reference.
Examples
Example 1: Various Declarations
dcl
dcl
dcl
dcl
dcl
dcl
dcl
dcl
char s;
num x y;
char s, num x y;
char(10) ar[3] x y z;
list mylist;
sashelp.fsp.collection.class obj3;
object obj4;
num m n, char(300) string, list newlist;
Each variable or array can be followed by an initial value or expression. The following
example declares and initializes various variables and arrays.
dcl
dcl
dcl
dcl
dcl
dcl
dcl
num
num
num
char(10)
char
list
list l =
x=1 y=20+x;
i1-i4=(1, 2, 3, 4);
arr(3)=(1, 2, 3);
s='abc';
sarr(3)=('abc', 'def', 'ghi');
mylist = {1, 'abc', 2, 'def'};
(100, 'abc', 200);
/* Initialize a list */
Example 2: Defining a Constant List with a Sublist
A constant list can be defined with a sublist.
init:
/* To edit a frame as the frame runs, */
/* it will display a pop-up menu
*/
/* when you press the ENTER key.
*/
dcl list myPopMenuList;
control enter;
/* Initialize a list with three pop-menu items: Select 1, Numeric */
/* and Character. Define a separator between items */
DELARRAY
/* 'Select 1' and 'Numeric'.
*/
myPopMenuList = { {text='Select 1',
helpText='This is a selection.',
mnemonic='S',
classifier = 107},
“-”,
“Numeric”,
“Character”};
return;
main:
rc = popmenu (myPopMenuList);
put rc=;
return;
term:
/* Delete myPopMenuList recursively to avoid a memory leak */
rc = dellist ( myPopMenuList, 'y');
return;
Note: The form of the physical filename depends on the host operating system.
See Also
•
“ARRAY” on page 220
•
“LENGTH (declaration)” on page 501
•
“USECLASS” on page 706
DELARRAY
Deletes a dynamic array
Category:
Array
Syntax
rc=DELARRAY(array);
Required Arguments
rc
indicates whether the operation was successful.
0
successful
≠0
not successful
Type: Numeric
array
is the dynamic array to delete. A non-dynamic array causes an error condition.
Type: Array
307
308
Chapter 13
•
SAS Component Language Dictionary
Details
The DELARRAY function deletes dynamic arrays. An array's contents cannot be
accessed after the array is deleted. Dynamic arrays are only accessible within the scope
that they are declared. In the following example, array B is not accessible outside of the
scope of the DO group:
DCL num a(*,*) rc;
a = makearray(5,5);
do;
DCL num b(*);
b = makearray(10);
end;
Comparisons
This example creates a 1-dimensional array of 3 elements, resizes it to 5 elements
(preserving the data), and then deletes the array.
DCL num a(*);
a = makearray(3);
do i=1 to dim(a);
a[i]=i;
end;
rc = redim(a,5);
put a=;
rc = delarray(a);
The output would be:
a[1]=1
a[2]=2
a[3]=3
a[4]=.
a[5]=.
See Also
•
“COPYARRAY” on page 282
•
“MAKEARRAY” on page 525
•
“REDIM” on page 610
DELETE
Deletes a member of a SAS data library or an external file or directory
Category:
Utility
Syntax
sysrc=DELETE(name<,type,<,password<,generation> > > );
DELETE
309
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
name
is the name of the member of the SAS data library or the physical pathname of an
external file or directory. If a one-level name is specified for a SAS data library
member, the library is assumed to be USER.
Type: Character
Optional Arguments
type
specifies the type of element to delete:
'ACCESS'
an access descriptor that was created using SAS/ACCESS software.
'CATALOG'
a SAS catalog or catalog entry. If a one- or two-level name is specified, the
catalog is deleted. If a four-level name is specified, the entry is deleted.
'DATA'
a SAS table. (This is the default.)
'FILE'
an external file or directory.
'MDDB'
an MDDB.
'VIEW'
a SAS table view.
Type: Character
password
is the password that is assigned to the SAS table when type is DATA.
Type: Character
generation
is the generation number of the SAS table that is being deleted.
Type: Numeric
Details
DELETE attempts to delete the specified member and returns a value indicating whether
the operation was successful. You can use DELETE to delete files or empty directories
that are external to a SAS session, as well as members of a SAS data library.
310
Chapter 13
•
SAS Component Language Dictionary
Examples
Example 1: Deleting Tables and Catalog Entries
Delete the SAS table LIB1.MYDATA and the SAS catalog entry
LIB2.CAT1.MYPROG.PROGRAM:
rc=delete('lib1.mydata');
rc=delete('lib2.cat1.myprog.program','catalog');
When deleting generation tables, if you delete the current (base) table without specifying
the generation parameter, all tables in the generation group are deleted. For example:
rc=delete('one');
/* Deletes all tables in the generation group named 'one'*/
If you specify the current (base) table using the generation parameter, only that table is
deleted. The youngest historical table becomes the new base. For example:
rc=delete('one','data',”,0);
/* Deletes only the table work.one (relative generation number=0) */
Example 2: Deleting Files
Delete an external file:
In UNIX:
/* delete a file in a different directory */
rc=delete('/local/u/abcdef/testfile','file');
In Windows:
/* delete a file in a different directory */
rc=delete('D:\testfile','file');
Example 3: Deleting Data Set Generations
Delete the third generation of a data set:
/* delete the third generation of the data set 'work.one' */
rc=delete('work.one','data',”,3);
See Also
“NEW” on page 558
DELITEM
Deletes an item from an SCL list
Category:
List
Syntax
list-id=DELITEM(list-id<,index> );
DELLIST 311
Required Argument
list-id
is the identifier of the list from which the item is to be deleted. The function returns
the list identifier that is passed in. An invalid list-id produces an error condition.
Type: Numeric or List
Optional Argument
index
is the position of the item in the list. The position can be specified as either a positive
or negative number. By default, index is 1 (the first item). If index is a positive
number, then the item is at position index from the beginning of the list. If index is a
negative number, then the item is at position ABS(index) from the end of the list. An
error condition results if the absolute value for index is zero or if it is greater than the
number of items in the list.
Type: Numeric
Details
The item to be deleted is specified by its position in the list that is passed in.
DELITEM does not make a copy of the list before deleting the specified item. The delete
operation is performed in place on the list, and the list identifier is returned.
When the item to be deleted is a sublist, DELITEM deletes the item but not the sublist,
because the sublist may be referenced by other SCL variables or lists.
An error condition results if
•
the item has the NODELETE attribute
•
the list has the NOUPDATE or FIXEDLENGTH attribute.
To check the attributes of a list or list item, use HASATTR. To change attributes, use
SETLATTR.
See Also
•
“DELLIST” on page 311
•
“DELNITEM” on page 313
•
“POPC, POPL, POPN, and POPO” on page 592
DELLIST
Deletes a list and optionally deletes all of its sublists
Category:
List
Syntax
rc=DELLIST(list-id<,recursively> );
312
Chapter 13
•
SAS Component Language Dictionary
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
list-id
is the identifier of the list to be deleted. An invalid list-id produces an error
condition.
Type: Numeric or List
Optional Argument
recursively
specifies whether to recursively delete all the list's sublists and all sublists of its
sublists.
'N'
Sublists are not deleted. (This is the default.)
'Y'
Sublists are deleted.
Type: Character
Details
A list's contents cannot be retrieved after the list is deleted.
If recursively is 'Y', DELLIST recursively deletes all sublists that do not have the
NODELETE attribute. For sublists that have the NODELETE attribute, the sublist
identifiers are removed from the deleted list, but the sublist is not deleted. Thus, you
should store list identifiers for sublists either in another list or in an SCL variable so that
you can access the lists later. All local lists that are not explicitly deleted are deleted
when the application ends, at the same time that SCL closes open tables and files.
CAUTION:
Be careful when deleting lists recursively because you may inadvertently delete
lists that are needed by other parts of the SCL program. Recursively deleting a
list deletes all of its sublists even if they are referenced in other SCL lists or by other
SCL variables. If you do not want a list to be deleted when it is a sublist item in a
deleted list, use SETLATTR to assign the NODELETE attribute to the sublist. See
“SETLATTR” on page 662 for a discussion of the NODELETE attribute.
To conserve memory, delete lists when they are no longer needed. Typically, a
DELLIST statement is placed in the termination section (TERM or FSETERM) of the
program. Although the program that creates a list is most often responsible for deleting
the lists that it creates, it does not have to delete them unless that is the appropriate
action for the application; it may return the list that it created to its caller.
The list is not deleted, and a non-zero value is returned to rc, if
•
the list has the NODELETE attribute
•
the list is the local or global environment list (the lists returned by the ENVLIST
function)
DELNITEM
•
313
list-id is a component identifier or a class list identifier.
To check attributes, use HASATTR. To change attributes, use SETLATTR.
If DELLIST fails because of a condition listed above, the list and/or sublists may be
partially cleared, and no further items or sublists are cleared.
See Also
•
“CLEARLIST” on page 262
•
“DELITEM” on page 310
•
“DELNITEM” on page 313
•
“SETLATTR” on page 662
DELNITEM
Deletes a named item from an SCL list
Category:
List
Syntax
list-id=DELNITEM(list-id,name,<occurrence<,start-index<,index<,forceup> > > > );
Required Arguments
list-id
is the identifier of the list from which the item is to be deleted. The function returns
the list identifier that is passed in. An invalid list-id produces an error condition.
Type: Numeric or List
name
is the name of the item to delete. Item names are converted to uppercase and trailing
blanks are ignored when searching the list for a matching name. Thus, the names
'abc' and 'Abc' are converted to 'ABC'.
Type: Character
Optional Arguments
occurrence
is the number of the occurrence of the named item to delete. The default, 1, specifies
the first occurrence of the item.
Type: Numeric
start-index
specifies where in the list to begin searching for the item. By default, start-index is 1
(the first item). If start-index is positive, then the search begins at position startindex items from the beginning of the list. If start-index is negative, then the search
begins at the item specified by ABS(start-index) items from the end of the list. An
error condition results if the absolute value of start-index is zero or if it is greater
than the number of items in the list.
Type: Numeric
314
Chapter 13
•
SAS Component Language Dictionary
index
specifies the variable to contain the position number of the deleted item. Index must
be initialized to a nonmissing value; otherwise, errors result.
Type
Numeric
Note
This parameter is an update parameter. See “Input, Output, and Update
Parameters” on page 38 for more information.
forceup
can have one of the following values:
'Y'
specifies a case-insensitive search, which overrides the
HONORCASE or NOHONORCASE list attribute.
'N'
specifies a search that uses the HONORCASE or
NOHONORCASE list attribute and is the default action for
lists when FORCEUP is not specified.
IGNORECASE
IGNORECASE is the alias for NOHONORCASE and is the
default for a list. But you can use the SETLATTR function to
set a list's attribute to HONORCASE.
Details
DELNITEM searches for a named item and deletes it from the list. Case is ignored only
if forceup is 'Y'; otherwise, it searches according to the list attribute HONORCASE
and NOHONORCASE.
If a list has the NOHONORCASE attribute, the case is also ignored.
If occurrence and start-index are both positive or both negative, then the search proceeds
forward from the start-index item. For forward searches, the search continues only to the
end of the list and does not wrap back to the front of the list. If occurrence or start-index
is negative, then the search is backwards. For backward searches, the search continues
only to the beginning of the list and does not wrap back to the end of the list.
DELNITEM does not make a copy of the list. The delete operation is performed in place
on the list. For example, the following statement deletes the first item named app in the
list identified by LISTID:
listid=delnitem(listid,'app');
When the item to be deleted is a sublist, DELNITEM deletes the item but not the sublist,
because the sublist may be referenced by other SCL variables or lists.
An error condition results if
•
the item has the NODELETE attribute
•
the list has the NOUPDATE or FIXEDLENGTH attribute
•
the named item is not found in the list.
To check the attributes of a list or list item, use HASATTR. To change these attributes,
use SETLATTR.
Example
The following code creates a list named A, adds four items to the list, and prints the list.
Then it deletes the third item in the list and prints the list again.
DELOBS
315
a=makelist();
rc=insertc(a,'a',-1,'var1');
rc=insertc(a,'b',-1,'var2');
rc=insertc(a,'c',-1,'var1');
rc=insertc(a,'d',-1,'var2');
call putlist(a,'Before deleting',0);
pos=0;
rc=delnitem(a,'var1',2,1,pos);
put pos=;
call putlist(a,'After deleting',0);
The results of this program are:
Before deleting(VAR1='a'
VAR2='b'
VAR1='c'
VAR2='d'
)[5]
POS=3
After deleting(VAR1='a'
VAR2='b'
VAR2='d'
)[5]
Note: [5] is the list identifier that was assigned when this example was tested and may
be different each time the example is run.
See Also
•
“DELITEM” on page 310
•
“DELLIST” on page 311
•
“LISTLEN” on page 512
•
“SETLATTR” on page 662
DELOBS
Deletes a row from a SAS table
Category:
SAS Table
Syntax
sysrc=DELOBS(table-id);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
316
Chapter 13
•
SAS Component Language Dictionary
table-id
is the identifier that was assigned when the SAS table was opened. If table-id is
invalid, the program halts.
Type: Numeric
Details
You must fetch a row before it can be deleted. Some functions that fetch a row include
FETCH, FETCHOBS, LOCATEC, LOCATEN, APPEND, DATALISTC, and
DATALISTN.
Example
Delete the current row from an open SAS table. (The example assumes that the table
identifier returned by the OPEN function was stored in the SCL variable MYDATAID.)
If the function is unable to delete the row, a message is displayed on the message line.
if (delobs(mydataid)) then _msg_=sysmsg();
See Also
•
“APPEND” on page 217
•
“DATALISTC and DATALISTN” on page 299
•
“FETCH” on page 368
•
“FETCHOBS” on page 369
•
“LOCATEC and LOCATEN” on page 519
DESCRIBE
Fills an SCL list with items of system information about a SAS table, view, or catalog entry
Category:
List
Syntax
sysrc=DESCRIBE(source-name,list-id<,type>);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
source-name
is the name of the table, view, or catalog entry.
Type: Character
DESCRIBE
317
list-id
contains the identifier of an existing list to contain the control's description. An
invalid list-id produces an error condition.
Type: Numeric or List
Optional Argument
type
specifies the type of control to be described:
'CATALOG'
SAS catalog entry (This is the default.) For three- or four-level names, the default
entry type is PROGRAM.
'DATA'
SAS table (This is the default for one- or two-level names.)
'VIEW'
SAS data view.
Type: Character
Details
Because DESCRIBE replaces the previous values in the list, the same list can be used
repeatedly.
The items of descriptive information are placed into the list as named items, and the
names of the list items are the names of the attributes described. Only the named
attributes that appear in the list are filled in.
The attributes that DESCRIBE can place in an SCL list are determined by the value of
type. If type is DATA or VIEW, then the items named in the list are attributes that are
returned by the ATTRN and ATTRC functions. If type is CATALOG, then the items
named in the list are DESC (the description of the catalog), EDESC (the extended
description of the catalog entry), CRDATE (the date that the entry was created), and
DATE (the date that the entry was last modified). CRDATE and DATE are SAS date
values.
For catalog entries, if a numeric list item named DATE exists in the list, then
DESCRIBE sets that item's values to a SAS date value. Otherwise, if DATE is a
character list item, then DESCRIBE assigns a formatted date string using the
MMDDYY10. format. Use ITEMTYPE to determine the type of a list item.
Example
Create an SCL list containing items named DESC and DATE. DESCRIBE fills the
DESC and DATE items in the list with information about the catalog entry
MYLIB.MYCAT.A.SCL.
init:
desc_list=makenlist('L','DESC','DATE');
/* set DATE to character list item */
rc=setnitemc(desc_list,' ','DATE');
rc=describe('MYLIB.MYCAT.A.SCL',desc_list,'CATALOG');
call putlist(desc_list);
return;
The output would be similar to:
318
Chapter 13
•
SAS Component Language Dictionary
(DESC='A.SCL' DATE='03/25/2000' )[5]
See Also
“ATTRC and ATTRN” on page 226
DEVLIST
Displays a selection list of graphic hardware devices and returns user selections
Category:
Selection List
Syntax
selections=DEVLIST(catalog-name,device<,message<,autoclose<,num-sel> > > );
Required Arguments
selections
are one or more user selections from the list, or blank if the selection list window is
closed and no selections are made.
Type: Character
catalog-name
is the catalog that lists the devices. Usually the catalog SASHELP.DEVICES is used
as catalog-name.
Type: Character
device
is the type of device to be listed:
'CAMERA'
lists device catalog entries for film recorders.
'DEFAULT'
returns the current device name, description, and type instead of displaying a list.
'EXPORT'
lists device catalog entries for device drivers that produce a graphics stream file.
'MONITOR'
lists device catalog entries for video displays.
'PLOTTER'
lists device catalog entries for plotters.
'PRINTER'
lists device catalog entries for printers.
Type: Character
Optional Arguments
message
is the text for a message to be displayed above the selection list. The default message
tells users to make up to the number of selections specified in num-sel.
Type: Character
DEVLIST 319
autoclose
specifies whether the selection list window closes automatically after a user makes a
selection when only one choice is allowed:
'Y'
closes the window automatically. (This is the default.)
'N'
leaves the window open until the user explicitly closes it.
This option is ignored when num-sel is not 1. However, use '' as a placeholder if
you are also specifying a value for num-sel.
Type: Character
num-sel
specifies the maximum number of items a user can select from the list. To display
the list for information purposes only (no selections allowed), specify 0. To specify
an unlimited number of selections, use a value that is larger than the number of
available selections about graphic device drivers such as 9999.
Type: Numeric
Details
The value in selections consists of a 40-character description, an 8-character device
name, and an 8-character device type. For additional details about graphic device
drivers, see SAS/GRAPH: Reference and the SAS online Help for SAS/GRAPH
software.
You can provide a default value or an initial selected value in the list by providing a
value for the selections variable before calling DEVLIST. If selections contains valid
entry names when the function is invoked, those names are automatically designated as
selected when the selection list is displayed.
If a user closes the selection list window without making a selection, then DEVLIST
returns a blank value unless there was an initial value for the selections variable before
DEVLIST was called.
When multiple selections are allowed, selections contains the first value selected from
the list. However, the values for all selections can be returned in the current result list, if
one is available. The current result list is a special SCL list that is automatically filled
with the values selected from a selection list. To use a current result list, use the
MAKELIST function to create the list, and use the CURLIST function to designate it as
the current result list. The current result list must exist before you call DEVLIST.
When DEVLIST is invoked, the current result list is cleared. After DEVLIST is invoked,
the result list contains the following named items:
TAG
identifies the list as one that was created by the DEVLIST function.
Type: Character
COUNT
contains either the number of selected elements, or 0 if a user makes no selections or
issues a CANCEL command in the list window.
Type: Numeric
DESC
contains the description of the selected device. There is one DESC element for each
selection. The value of DESC is in the case that was entered originally.
Type: Character
320
Chapter 13
•
SAS Component Language Dictionary
DEVICE
contains the name for each selected device. There is one DEVICE element for each
selection.
Type: Character
TYPE
contains the type of each selected device. There is one TYPE element for each
selection.
Type: Character
Examples
Example 1: Displaying the Printer Devices of a Catalog
Display a list of devices of type PRINTER that are available in the catalog
SASHELP.DEVICES. After the user selects one device from the list, the program uses
the SUBSTRING function to extract the individual items of information returned by
DEVLIST.
select=devlist('sashelp.devices','printer',
'Select a device.');
descript=substr(select,1,40);
device=substr(select,41,8);
devtype=substr(select,49,8);
Example 2: Using the Results of a DEVLIST
Use the current result list to process multiple selections:
listid=makelist();
rc=curlist(listid);
selection=devlist('sashelp.devices','printer',
'Select a device',' ',3);
n=getnitemn(listid,'COUNT');
do i=1 to n;
descript=getnitemc(listid,'DESC',i);
device=getnitemc(listid,'DEVICE',i);
devtype=getnitemc(listid,'TYPE',i);
put descript= device= devtype=;
end;
See Also
“COLORLIST” on page 265
DIALOG
Runs a FRAME entry that was created with SAS/AF software and disables all other windows
Category:
Modular Programming
Syntax
CALL DIALOG(entry ,<parameters>)
DIALOG 321
Required Argument
entry
is a FRAME entry to be displayed. It is specified as
entry.type
for a FRAME entry in the current catalog.
libref.catalog.entry.type
for a FRAME entry in a specified catalog.
Type: Character
Optional Argument
parameters
lists one or more parameters to pass to the called entry. For the called entry to accept
these parameters, it must contain a corresponding ENTRY statement.
Note: These parameters are update parameters. See “Input, Output, and Update
Parameters” on page 38 for more information.
Type: Numeric, Character
Details
DIALOG runs a FRAME entry, makes it the active entry, and disables all other
windows. When the called entry is exited, control returns to the calling program. With
the exception of disabling all other windows, DIALOG is similar to DISPLAY.
From the window created with the CALL DIALOG routine, you cannot execute a
SUBMIT statement with the CONTINUE option. See “Controlling What Happens After
a Submit Block Executes” on page 91.
DIALOG can pass parameters through the ENTRY statement to the called Frame entry.
Parameters can be numeric constants, character constants, variables, expressions, and
array variables.
Using DIALOG without any options in the associated ENTRY statement requires a strict
correspondence between DIALOG parameters and ENTRY statement arguments. The
arguments and parameters must agree in number, data type, and relative position. If you
pass an incorrect number of parameters or a parameter of the incorrect type, SCL halts
the execution of the program. The argument-parameter correspondence is less restrictive
when you use the options REST=, ARGLIST=, and OPTIONAL= in the ENTRY
statement.
Names listed in parameter do not have to match the argument names in the ENTRY
statement.
Parameters are passed in the following ways:
call-by-reference
passes window variables and local variables and allows values to be returned to the
calling program. This method allows the called program to modify values and then
return them. If you do not want to return the new values, use the NOCHANGE
routine. Or, if you do not want to return the new values for particular parameters, use
the INPUT option for that parameter in the ENTRY statement. Here is an example of
call-by-reference:
array employee{50};
call dialog(’b.frame’,var1,name,num,employee{1});
322
Chapter 13
•
SAS Component Language Dictionary
call-by-value
is used for all numeric constants, character constants, and expressions. It does not
allow values to be returned to the calling program. Here is an example of call-byvalue:
call dialog(’b.frame’,100,’hello’,x+y);
See Also
•
“DISPLAY” on page 326
•
“ENTRY” on page 346
•
“NOCHANGE” on page 566
•
“RETURN” on page 619
DINFO
Returns information about a directory
Category:
Directory
Syntax
attribute=DINFO(directory-id,info-item);
Required Arguments
attribute
contains the value of the information item, or a blank if info-item is invalid.
Type: Character
directory-id
is the identifier that was assigned when the directory was opened. If directory-id is
invalid, the program halts.
Type: Numeric
info-item
is the information item to be retrieved.
Type: Character
Details
DINFO returns the value of a system-dependent directory parameter. The available
information varies according to the operating system. See the SAS documentation for
your host operating system for information about system-dependent directory
parameters.
Use DOPTNAME to determine the names of the available system-dependent directory
information items. Use DOPTNUM to determine the number of directory information
items available.
DIRLIST
323
Example
Open the directory MYDIR, determine the number of directory information items
available, and retrieve the value of the last item:
/* Assign the fileref MYDIR to the */
/* pathname stored in the variable */
/* or entered in the DIRNAME field and open it.*/
rc=filename('mydir',dirname);
did=dopen('mydir');
numopts=doptnum(did);
foption=doptname(did,numopts);
charval=dinfo(did,foption);
rc=dclose(did);
See Also
•
“DOPTNAME” on page 334
•
“DOPTNUM” on page 335
•
“FINFO” on page 393
•
“FOPTNAME” on page 403
•
“FOPTNUM” on page 404
DIRLIST
Opens a host selection list window that lists members of one or more SAS data libraries, and returns a
user's selections
Category:
Selection List
Syntax
selections=DIRLIST(lib-spec,member-type,num-sel,prefix<,table-type<,sel-excl<,message> > > );
Required Arguments
selections
contains one or more user selections. Multiple selections are separated by blanks. By
default, selections is 200 bytes long. To accommodate values longer than 200 bytes,
explicitly declare selections with a longer length.
Type: Character
lib-spec
lists one or more librefs that are associated with particular SAS data libraries. To
include or exclude SAS data libraries, use a name specification style from “Name
Specifications for Arguments” on page 324. By default, SASHELP is not included
in the selection window.
Type: Character
member-type
lists one or more types of SAS data library members. For example, a few common
member-types are DATA, VIEW, and CATALOG. To include or exclude particular
324
Chapter 13
•
SAS Component Language Dictionary
member-types, use a name specification style from “Name Specifications for
Arguments” on page 324.
Type: Character
num-sel
is the maximum number of items that a user can select from the list. To display the
list for information purposes only (no selections allowed), specify 0. To specify an
unlimited number of selections, use a value such as 9999 that is larger than the
number of available selections.
Type: Numeric
prefix
specifies whether names that are selected are prefixed with the libref:
'Y'
Selected names are returned as libref.name.
'N' or ”
Selected names are returned as name.
Optional Arguments
table-type
lists one or more SAS table types. By default, the selection list displays members of
all SAS table types. To include or exclude specific table types, use a name
specification style from “Name Specifications for Arguments” on page 324. This
argument is ignored unless DATA is one of the values of member-type. For
information about table types, see the description of the TYPE= data set option in the
“TYPE= Data Set Option” in SAS Data Set Options: Reference.
Type: Character
sel-excl
lists one or more SAS data library members to include or exclude from the list. Use a
name specification style from “Name Specifications for Arguments” on page 324. If
prefix is N, then specify the name here as member. If prefix is Y, then specify the
name here as libref.member.
Type: Character
message
is the text for a message to be displayed above the selection list. The default message
tells users to make up to the number of selections specified in num-sel.
Type: Character
autoclose
is an obsolete argument but is retained for compatibility with earlier releases. If you
want to specify a value for num-sel, then specify “ as a placeholder for this
argument.
Details
Name Specifications for Arguments
For lib-spec, member-type, and table-type, use these guidelines for specifying names:
•
To specify one or more specific names, separate the names with a space.
•
To specify all names, use an asterisk (*) or a null string ('').
DIRLIST
•
325
To specify all names except those listed, use a NOT sign (^ or ¬) followed by one or
more names.
Usage
If a user closes the selection list window without making a selection, selections contains
a blank value unless that variable contained a valid value before DIRLIST was called.
The values for all selections can be returned in the current result list, if one is available.
The current result list is a special SCL list that is automatically filled with the values
selected from a selection list. To use a current result list, use the MAKELIST function to
create the list, and use the CURLIST function to designate it as the current result list.
The current result list must exist before you call the DIRLIST function.
When the function is invoked, the current result list is cleared. After DIRLIST is
invoked, the current result list contains the following named elements:
TAG
identifies the list as one that was created by DIRLIST.
Type: Character
COUNT
contains the number of selected items or contains 0 if a user makes no selections or
issues a CANCEL command in the list window.
Type: Numeric
NAME
contains the uppercase name of each selected catalog entry. If prefix is Y, then the
name is in the form libref.member. Otherwise, it is in the form member. There is one
NAME element for each selection made.
Type: Character
DESC
contains the description of each selected catalog entry. There is one DESC element
for each selection made. The value of DESC is in the case entered originally. If the
SAS system option DETAILS is in effect, then DESC contains the table label.
Type: Character
TYPE
contains the type of each selected library member. There is one TYPE element for
each selection.
Type: Character
Because some engines support mixed-case filenames, DIRLIST now retains the cases of
the returned selected items. This may cause your application to fail if your application
contains code that assumes the returned selection is uppercased. For example,
if (dirlist(dsid, 'TESTNDX')='NDXVAR')
must be changed to
if (upcase(dirlist(dsid, 'TESTNDX'))='NDXVAR'
If the application cannot be modified, you may need to specify the
VALIDVARNAME=V6 system option when you run the application to ensure that the
selections returned from the DIRLIST function will be uppercased.
326
Chapter 13
•
SAS Component Language Dictionary
Example: Display a List of Libraries
Display a selection list of SAS tables in the SAS libraries MYLIB1 and MYLIB2 except
MYLIB1.ANSWERS, and enable users to select up to three table names. The selections
are retrieved from the current environment list by using GETNITEMC.
listid=makelist();
rc=curlist(listid);
selections=dirlist('mylib1 mylib2','data',3,'Y',
' ','^ mylib1.answers');
n=getnitemn(listid,'COUNT');
do i=1 to n;
member=getnitemc(listid,'NAME',i);
descript=getnitemc(listid,'DESC',i);
memtype=getnitemc(listid,'TYPE',i);
put member= descript= memtype=;
end;
See Also
•
“CATLIST” on page 240
•
“FILELIST” on page 381
•
“LIBLIST” on page 504
DISPLAY
Runs a catalog entry that was created with SAS/AF software
Category:
Modular Programming and Object Oriented
Syntax
CALL DISPLAY(entry<,parameters> );
return-value=DISPLAY(entry<,parameters> );
Required Arguments
entry
is a display entry (FRAME, PROGRAM, SCL, MENU, HELP, or CBT) that was
created using SAS/AF software. It is specified as
entry-name
for a PROGRAM entry in the current catalog.
entry.type
for an entry of the specified type in the current catalog.
libref.catalog.entry
for a PROGRAM entry in the specified catalog.
libref.catalog.entry.type
for an entry of a specified type in a specified catalog.
Type: Character
DISPLAY 327
return-value
contains the value that is returned by the called entry. The data type for return-value
should match the data type for the called entry.
Type: Numeric, Character, List, Object, Class, or Interface
Optional Argument
parameters
lists one or more parameters to pass to the called entry. You can pass parameters to
FRAME, PROGRAM, and SCL entries. In order for the called entry to accept these
parameters, it must contain a corresponding ENTRY statement.
Type: Numeric, Character
Details
DISPLAY can run a FRAME, PROGRAM, SCL, MENU, HELP, or CBT entry and
make it the active entry. When the called entry is exited, control returns to the calling
program.
DISPLAY can pass parameters to a FRAME, PROGRAM, or SCL entry and receive a
return value. Parameters can be numeric constants, character constants, variables,
expressions, and array variables. Parameters are passed to the ENTRY statement in the
called entry.
Using DISPLAY without any options in the associated ENTRY statement requires a
strict correspondence between DISPLAY parameters and ENTRY statement arguments.
The arguments and parameters must agree in number, data type, and relative position. If
you pass an incorrect number of parameters or a parameter of the incorrect type, SCL
halts the execution of the program. The argument-parameter correspondence is less
restrictive when you use the options REST=, ARGLIST=, and OPTIONAL= in the
ENTRY statement. See “ENTRY” on page 346 for examples of these options.
Names listed in parameter do not have to match the argument names in the ENTRY
statement.
Parameters are passed in the following ways:
call-by-reference
enables the specified entry to change the values of the parameters. If you do not want
the values of the parameters to be modified, use the NOCHANGE routine. Or, if you
do not want to return the new values for specific parameters, use the INPUT option
for that parameter in the ENTRY statement. Here is an example of call-by-reference:
array employee{50};
call display('b.frame',var1,name,num,employee{1});
call-by-value
prevents the specified entry from changing the values of the parameters. Call-byvalue is used for all numeric constants, character constants, and expressions. Here is
an example of call-by-value:
call display('b.frame',100,'hello',x+y);
Note: Use CALL CBT to run CBT applications, because it provides more options used
by CBT entries. In general, you may want to use CALL GOTO instead of CALL
DISPLAY if you do not need control to return to the calling program. This may be
helpful for applications that have memory constraints.
328
Chapter 13
•
SAS Component Language Dictionary
Examples
Example 1: Passing Parameters
Use DISPLAY in program X to pass parameters to program Y. Program Y then declares
these arguments with an ENTRY statement. Variables I and S are call-by-reference
parameters, and the constant 1 is a call-by-value parameter.
X.SCL contains the following program:
INIT:
s = 'abcd';
i = 2;
call display('y.frame', i, 1, s);
/* At this point, after the return from Y, */
/* i=7 and s='abcde'
*/
put i= s=;
return;
MAIN:
TERM:
return;
Y.SCL contains the following program:
entry j c:num str:char;
init:
j = length(str) + c;
j = j + 2;
str = str || 'e';
c = 2;
return;
The following correspondence occurs:
•
The value of variable I passes to variable J.
•
The literal value 1 passes to variable C.
•
The value of variable S passes to variable STR.
After program Y runs, the values of variables J and STR are returned to the variables I
and S, respectively. The variable C cannot return a value, however, because the
corresponding parameter in DISPLAY is a constant.
Example 2: Passing Array Parameters by Reference
Use DISPLAY to pass array parameters by reference. In this example, the variables S
and A are call-by-reference parameters, and the constant 4 is a call-by-value parameter.
X.SCL contains the following program:
array a{4} 8;
INIT:
a{1} = 1; a{2} = 2; a{3} = 3; a{4} = 4;
s = 0;
call display('y.frame', s, a, 4);
/* At this point, after the return
from Y, */
/* s=10, a{1}=2, a{2}=4, a{3}=6,
a{4}=8.
*/
put s= a=;
return;
DISPLAYED
329
MAIN:
TERM:
return;
Y.SCL contains the following program:
array arr{*} 8;
entry sum arr[*] len:num;
INIT:
do i = 1 to len;
sum = sum + arr{i};
arr{i} = 2 * arr{i};
end;
return;
The following correspondence occurs:
•
The value of variable S passes to variable SUM.
•
The array variable A is passed to the array variable ARR.
•
The literal value 4 passes to variable LEN.
After program Y runs, the value of the variable SUM is returned to the variable S, and
the values in the array ARR are returned to the corresponding values in the array A. The
variable LEN cannot return a value, however, because the corresponding parameter in
DISPLAY is a constant.
See Also
•
“DIALOG” on page 320
•
“ENTRY” on page 346
•
“GOTO” on page 439
•
“INPUTC and INPUTN” on page 469
•
“NOCHANGE” on page 566
•
“RETURN” on page 619
DISPLAYED
Reports whether a control or field is currently visible
Category:
Control or Field
Syntax
rc=DISPLAYED(wvar-name);
Required Arguments
rc
indicates whether the FRAME entry control or field is visible:
1
visible
0
not visible
330
Chapter 13
•
SAS Component Language Dictionary
Type: Numeric
wvar-name
is the name of a control or field. This name cannot be an element of an array or an
expression. An invalid wvar-name halts the program.
Type: Character
Details
In SAS/AF applications, DISPLAYED reports whether a control is currently visible or
whether it has the NONDISPLAY attribute. In FSEDIT, DISPLAYED tells you whether
a field is visible on the current screen of a multiscreen application, regardless of whether
the control has the NONDISPLAY attribute. This function is useful in multiscreen
applications in which the application developer wants to be on a specific screen for a
field.
If a control is not currently displayed, then your application can use the EXECCMD
routine to issue scrolling commands to change the screen position or to issue scrolling
commands that are specific to the procedure (for example, the =n command in the
FSEDIT procedure).
The control or field cannot be an element of an array. To report this information for an
array element, use FIELD instead.
FRAME entry controls can also use the _isDisplayed or _isHidden method.
Example
Test whether the SALARY field is displayed on the current screen of an FSEDIT
application. If not, issue an FSEDIT scrolling command to display the screen that
contains the field:
if (displayed(salary)=0) then
call execcmd('=salary');
See Also
•
“ERROR” on page 352
•
“ERROROFF” on page 353
•
“ERRORON” on page 354
•
“FIELD” on page 373
•
“MODIFIED” on page 545
DMWINDOW
Sets the color and highlighting for lines in the OUTPUT and LOG windows
Category:
Window
Syntax
rc=DMWINDOW(window-name,line-type,color,attribute);
DMWINDOW
331
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
window-name
is the window for which you want to assign colors and display attributes:
'OUTPUT'
the OUTPUT window
'LOG'
the LOG window
Type: Character
line-type
is the output area to which the colors and highlighting attributes are to be assigned:
'DATA'
Data line
'ERROR'
Error line
'NOTES'
Notes line (LOG window only)
'SOURCE'
Source line (LOG window only)
'WARNING'
Warning line (LOG window only)
'BYLINE'
Byline line (OUTPUT window only)
'HEADER'
Header line (OUTPUT window only)
'TITLE'
Title line (OUTPUT window only)
Type: Character
color
is a color name: BLACK, BLUE, BROWN, CYAN, GRAY, GREEN, MAGENTA,
ORANGE, PINK, RED, WHITE, or YELLOW. SASCOLOR window elements can
also be used for color.
Type: Character
attribute
is a display attribute: NONE, BLINKING, HIGHLIGHT, HIREV, REVERSE, or
UNDERLINE. If you specify a SASCOLOR window element for color, then
attribute is ignored, because the SASCOLOR window element contains a display
attribute.
Type: Character
332
Chapter 13
•
SAS Component Language Dictionary
Details
The device must support the specified color or highlighting attribute in order for SAS to
enable the attribute.
Example
Set the highlighting attribute of the title line in the OUTPUT window to blinking and set
its color to yellow:
rc=dmwindow('output','title','yellow','blinking');
DNUM
Returns the number of members in a directory
Category:
Directory
Syntax
nval=DNUM(directory-id);
Required Arguments
nval
contains the number of members in the directory.
Type: Numeric
directory-id
is the identifier that was assigned when the directory was opened. If directory-id is
invalid, the program halts.
Type: Numeric
Details
You can use DNUM to determine the largest member number that can be passed to
DREAD.
Example
Open the directory MYDIR, determine the number of members, and close the directory:
/* Assign the fileref MYDIR to the
/* filename stored in the variable DIRNAME
/* and open it.
rc=filename('mydir',dirname);
dirid=dopen('mydir');
memcount=dnum(dirid);
rc=dclose(dirid);
See Also
“DREAD” on page 336
*/
*/
*/
DOPEN
333
DO
Designates a group of statements to be executed as a unit
Category:
Note:
Control Flow
SAS Statement with limitations in SCL
Syntax
DO do-clause;
END;
Details
The following forms of the do-clause are supported:
iterative DO
executes a group of statements repetitively, based on the value of an index variable.
However, the form DO i=item-1, . . . , item-n is not supported.
DO UNTIL
executes a group of statements repetitively until a condition is true.
DO WHILE
executes a group of statements repetitively as long as a condition is true.
The form DO OVER is not supported.
To force the statements in a DO group to stop executing, you can use the SCL statements
CONTINUE or LEAVE.
For details about the DO statement in the Base SAS language, see SAS Statements:
Reference.
See Also
•
“CONTINUE” on page 272
•
“LEAVE” on page 494
DOPEN
Opens a directory
Category:
Directory
Syntax
directory-id=DOPEN(fileref);
Required Arguments
directory-id
contains the return code for the operation:
334
Chapter 13
•
SAS Component Language Dictionary
0
indicates that the directory could not be opened.
>0
is the identifier that was assigned to the opened directory.
Type: Numeric
fileref
is the fileref that is assigned to the directory.
Type: Character
Details
DOPEN opens a directory and returns a directory identifier value (a number greater than
0), which can then be used to identify the open directory to other SCL functions. The
directory to be opened must be identified by a fileref. You must associate a fileref with
the directory before calling DOPEN.
You can assign filerefs by using either the FILENAME statement or the FILENAME
function in SCL. Under some operating systems, you can also use system commands to
assign filerefs.
Operating Environment Information
The term directory used in the description of this function and related SCL functions
refers to an aggregate grouping of files that are managed by the host operating
system. Different host operating systems identify such groupings with different
names, such as directory, subdirectory, MACLIB, or partitioned data set. See the
SAS documentation for your operating environment for details.
Example
Assign the fileref MYDIR to a directory. Then open the directory, determine how many
system-dependent directory information items are available, and close the directory.
DIRNAME is an SCL variable with a value that represents the actual name of the
directory in the form required by the host operating system.
rc=filename('mydir',dirname);
did=dopen('mydir');
infocnt=doptnum(did);
rc=dclose(did);
See Also
•
“DCLOSE” on page 302
•
“FOPEN” on page 401
•
“MOPEN” on page 548
DOPTNAME
Returns the name of a directory attribute
Category:
Directory
DOPTNUM
335
Syntax
attribute=DOPTNAME(directory-id,attribute-number);
Required Arguments
attribute
contains the directory option. If nval is out-of-range, the program halts and attribute
contains the value that it held before the program halt.
Type: Character
directory-id
contains the identifier that was assigned when the directory was opened. If directoryid is invalid, the program halts.
Type: Numeric
attribute-number
is the sequence number of the option.
Type: Numeric
Details
DOPTNAME works only if the directory was previously opened by the DOPEN
function. The names and nature of directory information items vary depending on the
operating system. The number of attributes that are available for a directory also varies
depending on the operating system.
Example
Open the directory identified by the fileref MYDIR, retrieve all system-dependent
directory information items, write them to the SAS log, and then close the directory:
/* Assign the fileref MYDIR to the */
/* filename stored in the variable DIRNAME
/* and open it.
rc=filename('mydir',dirname);
dirid=dopen('mydir');
numitems=doptnum(dirid);
do j=1 to numitems;
opt=doptname(dirid,j);
put 'Directory information=' opt;
end;
rc=dclose(dirid);
See Also
•
“DINFO” on page 322
•
“DOPTNUM” on page 335
DOPTNUM
Returns the number of information items that are available for a directory
Category:
Directory
*/
*/
336
Chapter 13
•
SAS Component Language Dictionary
Syntax
num-attributes=DOPTNUM(directory-id);
Required Arguments
num-attributes
contains the number of available directory information items. If an error condition
occurs, the program halts and num-attributes contains the value that it held before
the program halt.
Type: Numeric
directory-id
contains the identifier that was assigned when the directory was opened. If directoryid is invalid, the program halts.
Type: Numeric
Details
DOPTNUM works only if the directory was previously opened by the DOPEN function.
Example
Retrieve the number of system-dependent directory information items that are available
for the directory MYDIR and then close the directory:
/* Assign the fileref MYDIR to the
/* filename stored in the variable DIRNAME
/* and open it.
rc=filename('mydir',dirname);
dirid=dopen('mydir');
infocnt=doptnum(dirid);
rc=dclose(dirid);
See Also
•
“DINFO” on page 322
•
“DOPTNAME” on page 334
DREAD
Returns the name of a directory member
Category:
Directory
Syntax
name=DREAD(directory-id,member-num);
*/
*/
*/
DROPNOTE 337
Required Arguments
name
contains either the name of the member, or a blank if an error occurs (for example, if
nval is out-of-range).
Type: Character
directory-id
contains the identifier that was assigned when the directory was opened. If directoryid is invalid, the program halts.
Type: Numeric
member-num
is the sequence number of the member within the directory.
Type: Numeric
Details
Use DNUM to determine the highest possible member number that can be passed to
DREAD. DREAD works only if the directory was previously opened by the DOPEN
function.
Example
Open the directory identified by the fileref MYDIR, retrieve the number of members and
place the number in the variable MEMCOUNT, retrieve the name of the last member
and place the name in the variable LSTNAME, and then close the directory:
/* Assign the fileref MYDIR to the
/* filename stored in the variable DIRNAME
/* and open it.
rc=filename('mydir',dirname);
dirid=dopen('mydir')
lstname='';
memcount=dnum(dirid);
if (memcount>0) then
lstname=dread(dirid,memcount);
rc=dclose(dirid);
See Also
•
“DNUM” on page 332
•
“DOPEN” on page 333
DROPNOTE
Deletes a note marker from either a SAS table or an external file
Category:
SAS Table
Syntax
rc=DROPNOTE(table-id|file-id,note-id);
*/
*/
*/
338
Chapter 13
•
SAS Component Language Dictionary
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
table-id or file-id
contains the identifier that was assigned when the table or external file was opened.
If this variable contains an invalid value, the program halts.
Type: Numeric
note-id
contains the identifier that was assigned by the NOTE or FNOTE function. If note-id
contains an invalid value, the program halts.
Type: Numeric
Details
DROPNOTE deletes a marker that was set by NOTE or FNOTE.
Example
Open the SAS table MYDATA, fetch the first row, and set a note ID at the beginning of
the table. Return to the first row by calling POINT, and then delete the note ID by
calling DROPNOTE.
dsid=open('mydata','i');
rc=fetch(dsid);
noteid=note(dsid);
/* more SCL statements */
rc=point(dsid,noteid);
rc=fetch(dsid);
rc=dropnote(dsid,noteid);
See Also
•
“FNOTE” on page 398
•
“FPOINT” on page 406
•
“NOTE” on page 567
•
“POINT” on page 591
DSID
Searches for a SAS table name and returns the table identifier
Category:
SAS Table
DSID
339
Syntax
dsid=DSID(<table-name<,mode<,nth<,gen-num> > > > );
Required Argument
dsid
contains either the identifier for the table, or
0
if the table is not currently open, if the table is not open in the requested
mode, or if no nth open occurrence exists.
<0
if an error occurs. SYSMSG contains the error text.
Type: Numeric
Optional Arguments
table-name
names the SAS table to search for. The default is _LAST_, which is the last table
that was created in the current SAS session. A one-level name is assumed to be a
SAS table name in the default SAS data library, WORK. A two-level name is
assumed to be libref.table.
Type: Character
mode
specifies whether to limit the search to tables that are open in one of the modes listed
below. If mode is not specified, DSID returns the dsid for the first occurrence of
table-name that is open in any mode. Values for mode are
'I'
INPUT mode, allows random access if the engine supports it; otherwise,
defaults to IN mode.
'IN'
INPUT mode, reads sequentially and allows revisiting rows.
'IS'
INPUT mode, reads sequentially but does not allow revisiting rows.
'N'
NEW mode, creates a new SAS table.
'U'
UPDATE mode, allows random access if the engine supports it;
otherwise, defaults to UN mode.
'UN'
UPDATE mode, reads sequentially and allows revisiting rows.
'US'
UPDATE mode, reads sequentially but does not allow revisiting rows.
'V'
UTILITY mode, allows modification of column attributes and indexes
that are associated with the SAS table.
For more information about open modes, see “OPEN” on page 574.
Type: Character
nth
specifies which occurrence of table-name opened in the specified mode to search for.
By default, the search returns the first occurrence.
Type: Numeric
gen-num
is the generation number of the SAS table for which the DSID is returned.
Type: Numeric
340
Chapter 13
•
SAS Component Language Dictionary
Details
DSID searches all SAS tables that are currently open. This function is useful for
accessing table identifiers across entries.
Examples
Example 1: Working with Several Tables
Open several SAS tables and find the first occurrence in various modes:
/* Open several SAS tables, varying the open mode */
dsid1 = open('sasuser.class', 'I');
dsid2 = open('sasuser.class', 'U');
dsid3 = open('sasuser.class', 'U');
dsid4 = open('sasuser.houses', 'U');
dsid5 = open('sasuser.class', 'I');
dsid6 = open('sasuser.houses', 'U');
dsid7 = open('sasuser.houses', 'I');
dsid8 = open('sasuser.class', 'U');
/* Find the first occurrence open in any mode.*/
first = DSID( 'sasuser.houses' );
put first=;
/* Find the first occurrence open in 'I' */
firstI = DSID( 'sasuser.houses', 'I' );
put firstI=;
/* Find the second occurrence open in 'I' */
secondI = DSID( 'sasuser.class', 'I', 2 );
put second=;
/* Return the fourth occurrence open in 'U' */
secondU = DSID( 'sasuser.class', 'U', 4 );
put secondU=;
This example produces the following output:
first=4
firstI=7
secondI=5
secondU=0
Example 2: Returning the DSID of a Generation Data Set
The following code returns the DSID of the SAS table WORK.ONE#003.
dsid=DSID('work.one','IN',1,3);
See Also
“OPEN” on page 574
DSNAME
Returns the SAS table name that is associated with a table identifier
Category:
SAS Table
ENDBLOCK
341
Syntax
table-name=DSNAME(<table-id> );
Required Argument
table-name
contains either the table name that is associated with the specified table-id value, or a
blank if an invalid value is specified.
Type: Character
Optional Argument
table-id
contains the identifier that was assigned when the table was opened. If DSNAME is
called from FSEDIT, FSBROWSE, or FSVIEW, this value is optional. If table-id is
not specified in an FSEDIT or FSVIEW application, then DSNAME returns the
name of the current table. If table-id is not specified in a SAS/AF application, then
DSNAME returns a blank.
Type: Character
Example:
•
Determine the name of the SAS table that is associated with the table identifier
TABLEID and display this name on the message line:
_msg_='The open table is '||dsname(tableid)||'.';
•
In an FSEDIT or FSVIEW SCL program, display on the command line the name of
the table that is currently being edited:
_msg_='The table being edited is '||dsname()||'.';
See Also
“OPEN” on page 574
ENDBLOCK
Closes the window that is created by the BLOCK function
Category:
Window
Syntax
CALL ENDBLOCK();
Example
Create a menu that contains four choices. The first row of blocks contains two blocks
with the labels Outline and Index. The second row contains two blocks with the labels
Compare Files and Calendar. No third row of blocks is displayed. The memory that was
used in displaying the menu is freed when the ENDBLOCK routine is executed and the
window is closed.
342
Chapter 13
•
SAS Component Language Dictionary
INIT:
choice=block('Writers Toolbox','Main Menu',6,
'Outline','Index','','',
'Compare Files','Calendar','','',
'','','','');
...more SCL statements...
return;
MAIN:
...more SCL statements...
return;
TERM:
call endblock();
return;
See Also
“BLOCK” on page 233
ENDCATCH
Ends a CATCH statement block
Category:
Control Flow
Syntax
ENDCATCH;
Comparisons
The ENDCATCH statement marks the end of a CATCH block.
See Also
“CATCH” on page 239
ENDCLASS
Ends a CLASS statement block
Category:
Object Oriented
Syntax
ENDCLASS;
Details
The ENDCLASS statement marks the end of a CLASS block in an SCL program. Use
ENDCLASS to designate the end of a block of SAS statements that define a class.
ENDMETHOD
343
See Also
“CLASS” on page 249
ENDLEGEND
Closes the LEGEND window
Category:
Legend
Syntax
CALL ENDLEGEND();
Details
If the LEGEND window is not currently displayed, the routine has no effect.
For an example of using ENDLEGEND as well as other functions that manipulate the
LEGEND window, see “LEGEND” on page 497.
See Also
•
“POPLEGEND” on page 595
•
“PUSHLEGEND” on page 603
•
“PUTLEGEND” on page 606
ENDMETHOD
Ends a METHOD statement block
Category:
Modular Programming and Object Oriented
Syntax
ENDMETHOD;
Details
The ENDMETHOD statement marks the end of a method block in an SCL program. Use
ENDMETHOD with a METHOD statement to indicate a block of statements that can be
called by the METHOD routine. When the method block is executed, control returns to
the calling program when ENDMETHOD is encountered.
Example
End a METHOD block:
METHOD;
...SCL statements...
endmethod;
344
Chapter 13
•
SAS Component Language Dictionary
See Also
“METHOD (define)” on page 535
ENDPACKAGE
Ends a PACKAGE statement block
Category:
Object Oriented
Syntax
ENDPACKAGE;
Comparisons
The ENDPACKAGE statement marks the end of a PACKAGE block. Use
ENDPACKAGE to designate the end of a block of ITEM statements that define a
package.
See Also
“PACKAGE” on page 583
ENDSUBMIT
Ends statements to be submitted to SAS software for execution
Category:
Submit Block
Syntax
ENDSUBMIT;
Details
The ENDSUBMIT statement marks the end of a SUBMIT block in an SCL program.
Use ENDSUBMIT with SUBMIT to indicate a block of SAS statements to submit to
SAS software for execution.
The ENDSUBMIT statement instructs SCL to stop collecting statements in the
PREVIEW buffer and to submit the collected statements, based on the options that were
specified for the SUBMIT statement.
Example
Use SUBMIT to invoke the PRINT procedure and use ENDSUBMIT to mark the end of
the SUBMIT block:
submit immediate;
data one;
do x=1 to 10;
output;
ENDTABLE 345
end;
run;
proc print;
run;
endsubmit;
See Also
“SUBMIT” on page 682
ENDTABLE
Stops the processing of the getrow section of a dynamic extended table
Category:
Extended Table
Syntax
CALL ENDTABLE();
Details
The ENDTABLE routine stops the processing of the getrow section of a dynamic
extended table. A dynamic extended table is a table whose maximum number of rows is
determined when the program executes. Call the ENDTABLE routine from the getrow
section of the SCL program when the end of the extended table has been reached.
Because you can define extended tables only in SAS/AF software, you cannot use
ENDTABLE in FSEDIT or FSVIEW programs.
The ENDTABLE routine marks only the end of the table for this invocation of the
GETROW label. If the user issues a scroll command, the GETROW label is driven again
until ENDTABLE is called. This allows the size of the table to change dynamically.
Example
In this example, data for the extended table comes from the open SAS table that is
identified by the value in the variable DSID. The _CURROW_ variable, which identifies
the current row of the extended table, specifies which row to fetch. When the value of
_CURROW_ exceeds the number of rows in the table, FETCHOBS returns a nonzero
value, which indicates that the end of the extended table has been reached. ENDTABLE
is then called to stop the processing of the GETROW label.
GETROW:
...SCL statements...
if (fetchobs(dsid,_currow_) =−1) then
call endtable();
else do;
...more SCL statements...
end;
return;
See Also
•
“CURTOP” on page 297
346
Chapter 13
•
SAS Component Language Dictionary
•
“SETROW” on page 671
•
“TOPROW” on page 696
ENDUSECLASS
Ends a USECLASS statement block
Category:
Object Oriented
Syntax
ENDUSECLASS;
Details
The ENDUSECLASS statement marks the end of a USECLASS block in an SCL
program. Use ENDUSECLASS with USECLASS to designate a block of SAS
statements that define methods for a class that was previously defined in the Class
Editor.
See Also
“USECLASS” on page 706
ENTRY
Receives parameters from the DISPLAY function or routine
Category:
Modular Programming and Object Oriented
Syntax
ENTRY <argument-list> <RETURN=data-type>
<OPTIONAL=argument-list | <ARGLIST=arg-list-id | REST=rest-list-id> >;
Optional Argument
argument-list
lists one or more sets of arguments, with each set specified as follows:
•
var-list <: INPUT |UPDATE |OUTPUT> :data-type
var-list
lists one or more variables to which the parameter in the corresponding position
in the DISPLAY routine or function is passed. For details, see “DISPLAY” on
page 326.
INPUT | I
specifies that, at run time, the variable contains the value that is copied from the
corresponding parameter of the calling program. However, when the program
finishes, the value is not copied back to the calling program. This is equivalent to
using CALL NOCHANGE() in the calling program.
ENTRY
347
UPDATE | U
specifies that, at run time, the variable contains the value that is copied from the
corresponding parameter of the calling program. When the program finishes, the
value is copied back to that parameter (unless CALL NOCHANGE is specified).
OUTPUT | O
specifies that, when the program finishes, the value is copied back to the
corresponding parameter in the calling program. An error condition results if the
corresponding parameter in the calling program is a constant, because a constant
cannot receive a value.
data-type
specifies the data type of the variable. Any valid SCL data type may be specified.
A named data type (for example, CHAR or LIST) must be preceded by the :
delimiter. The delimiter is optional for unnamed data types (for example, $).
arg-list-id
contains the identifier for the SCL list that will contain all the arguments passed
to the ENTRY statement. This includes all optional arguments.
Type: List
rest-list-id
contains the identifier for the SCL list that will contain all arguments that are
passed to the ENTRY statement but are not explicitly specified in argument-list
for either ENTRY or OPTIONAL=.
Type: List
Details
The ENTRY statement receives parameters from the DISPLAY routine or function. It
can also return a value if the ENTRY statement contains both the RETURN= option to
declare the data type of the returned value and a RETURN statement that specifies either
the variable containing the value or the literal value to be returned.
To be compatible with the applications built in earlier releases of SAS software, the :
delimiter is optional for variables that are assigned unnamed data types (for example, $),
but it is required for variables that are assigned named data types. The following
example shows a variety of data type declarations:
ENTRY
char1 :$20
char2 $20
char3 :input :char(20)
char4 char5 :char
num1
:8
num2
8
num3
:num
mylist :list
myobj :object
mybutton :mylib.mycat.button.class return=char;
RETURN=data-type enables you to return a value to the calling program. An error
condition is produced if data-type is not the same as the type of data to be returned to the
calling program. In addition, you must pass a parameter in the (call) display statement if
you want a return value passed back to the calling program. Otherwise, if you do not
pass a parameter on the (call) display statement, no return value is passed back to the
calling program. Use a RETURN statement in the program to specify the value to return.
When there are no options in the ENTRY statement, there is a strict correspondence
between DISPLAY parameters and ENTRY statement arguments. The arguments and
348
Chapter 13
•
SAS Component Language Dictionary
parameters must agree in number, data type, and relative position. If you pass an
incorrect number of parameters or a parameter of the incorrect type, SCL stops
executing the program. The correspondence of arguments to parameters is less restrictive
when you use the options REST=, ARGLIST=, and OPTIONAL= in the ENTRY
statement.
OPTIONAL= enables you to specify a list of optional arguments that are used only if the
calling program supplies the corresponding parameters in the DISPLAY parameter list.
If the corresponding parameters in the DISPLAY routine are not supplied, then the
optional arguments are initialized to missing values.
ARGLIST= and REST= enable you to pass a variable number of parameters to the
ENTRY statement. You determine the types and order of the variable arguments. The
lists identified by arg-list-id and rest-list-id are created automatically when the entry is
called, and they are deleted automatically when the entry ends. When arrays are passed
as parameters, the array is expanded into individual items, and these items are inserted
into the arg-list-id and rest-list-id lists. ARGLIST= and REST= are mutually exclusive,
so you can use only one or the other.
The called program can modify all call-by-reference arguments that it receives.
However, it cannot modify any call-by-value arguments. For a description of call-byreference and call-by-value, see “DISPLAY” on page 326 .
By default, values for call-by-reference arguments are returned to the calling program. If
you want a called program to receive values but not to return values to its calling
program, use the NOCHANGE routine. Or, you can use the INPUT, OUTPUT, or
UPDATE option for each variable to specify how its value is passed and returned.
An SCL program with ENTRY statement arguments cannot be executed by itself due to
the uninitialized arguments. To test a program that receives parameters via the ENTRY
statement, run it with the SCL debugger. The debugger enables you to initialize all the
ENTRY arguments before program execution starts.
Examples
Example 1: Returning a Value from the ENTRY Statement
B.SCL contains the following ENTRY statement, which uses several numeric
arguments:
entry x y z u v :i :num return=num;
INIT:
total=x+y+z+u+v;
return(total);
A.SCL contains
total=display('b.scl',1,2,3,4,5);
put total=;
The output of A.SCL is
total=15
Example 2: Using ENTRY with OPTIONAL=
B.SCL contains the following ENTRY statement, which defines multiple character
variables:
entry x
:char(10)
y z :num
ENTRY
349
optional=u v w :num ;
INIT:
put x= y= z= u= v= w=;
return;
Suppose A.SCL contains
call display('b.program','one',2,3,4,5);
The output would be
X='one' Y=2 Z=3 U=4 V=5 W=.
Example 3: Using ENTRY with ARGLIST=
B.SCL contains the following ENTRY statement, declaring both numeric, character, and
list variables:
entry x
:char(10)
y z :num
optional=u v
:num
arglist=mylist;
INIT:
put x= y = z= u= v=;
call putlist(mylist);
return;
Suppose A.SCL contains
call display('b.scl','one',2,3,4,5);
The output would be
x='one'
y=2
z=3
u=4
v=5('one' 2 3 4 5) [list-id]
Example 4: Using ENTRY with ARGLIST=
Suppose B.SCL contains
entry arglist=mylist;
INIT:
call putlist(mylist);
return;
Suppose A.SCL contains
call display('b.scl','one',2,3,4,5);
The output would be
('one' 2 3 4 5) [list-id]
Example 5: Using ENTRY with REST=
B.SCL contains the following ENTRY statement, which declares numeric variables:
entry x y :num
rest=mylist;
INIT:
put x= y=;
call putlist(mylist);
350
Chapter 13
•
SAS Component Language Dictionary
return;
Suppose A.SCL contains
call display('b.scl',1,2,3,4,5);
The output would be
x=1
y=2
(3 4 5) [list-id]
Example 6: Using ENTRY with OPTIONAL= and REST=
B.SCL contains the following ENTRY statement, which declares both numeric and
character variables along with parameter Z, which is optional:
entry x y :num optional=z :num rest=mylist;
INIT:
put x= y= z=;
call putlist(mylist);
return;
Suppose A.SCL contains
call display('b.scl',1,2,3,4,5);
The output would be
x=1
y=2
z=3
(4 5) [list-id]
See Also
•
“DISPLAY” on page 326
•
“NOCHANGE” on page 566
•
“METHOD (define)” on page 535
•
“RETURN” on page 619
ENVLIST
Returns the list identifier of an SCL environment list
Category:
List
Syntax
list-id=ENVLIST(<envlist-type> );
Required Argument
list-id
contains the identifier of the SCL environment list.
Type: Numeric or List
ENVLIST 351
Optional Argument
envlist-type
specifies which environment list to return:
'G'
returns the identifier for the global environment list.
'L'
returns the identifier for the local environment list. (This is the default.)
Type: Character
Details
Global Environment List
When the SAS session starts, a global environment list that persists for the entire session
is created. When a SAS/AF or FSEDIT application starts executing, a local environment
list is created for that application. This local environment list persists for the duration of
that application and is available to each program that runs in that application (for
example, a program that is invoked by the DISPLAY routine).
Environment lists are special lists that can contain numeric items, character items, and
sublist items. You use the item names to fetch the items. You can use the item names to
fetch the items. Environment lists provide a means of creating global variables that can
be shared among different SCL programs, much like macro variables. However, unlike
macro variables, the names in an environment list do not have to be valid SAS names,
and the values in an environment list can be other lists, if you want to associate a lot of
data with a single name. For example, you can read the contents of a small SAS table
into a list and place the contents in the global environment list so that other SCL
programs do not have to read the table to fetch data.
You can also insert items that do not have names.
The Local Environment List
The local environment list, which is returned by ENVLIST('L'), contains data that is
available only to the current application. Each executing application has its own unique
local environment list. Both the contents of an application's environment list and the list
itself are deleted when the application ends.
The Global Environment List
The global environment list, which is returned by ENVLIST('G'), contains data that all
SAS applications can share during the same SAS session. The data remains in the global
environment list until an SCL program explicitly removes it. Thus, after one application
puts data into the global environment list, the application can exit, and another
application can fetch the data.
You can insert only global lists into the global environment list. Global lists are created
with MAKELIST or MAKENLIST (using the 'G' visibility value), or they can be new
lists that have been copied from other global lists. A fatal error results if you try to insert
a local list into the global list.
Recommendations for Modifying Environment Lists
It is strongly recommended that you insert only named items into environment lists and
that you choose names that are unambiguous. If you add items that have simple names,
other applications are more likely to unknowingly use the same name and to accidentally
overwrite your data.
352
Chapter 13
•
SAS Component Language Dictionary
See Also
•
“CURLIST” on page 293
•
“DELLIST” on page 311
•
“MAKELIST” on page 527
•
“MAKENLIST” on page 528
ERROR
Reports whether a FRAME entry control or field contains an invalid value
Category:
Control or Field
Syntax
rc=ERROR(wvar-name);
Required Arguments
rc
indicates whether the FRAME entry control or field in the window is in error:
1
in error
0
not in error
Type: Numeric
wvar-name
is the name of a FRAME entry control or field in the window. This argument cannot
be an expression.
Type: Character
Details
Use ERRORON and ERROROFF to set and reset error conditions for the FRAME entry
control or field.
The FRAME entry control or field cannot be an element of an array. To report this
information for an array element, use FIELD instead.
FRAME entry controls can also use the _inError method.
Examples
Example 1: Using ERROR to Report Invalid Values
Specify the CONTROL statement with the ERROR option in the INIT section of the
program. The statements in the MAIN section are submitted only if the FRAME entry
control OBJ1 is not in error.
INIT:
control error;
return;
ERROROFF 353
MAIN:
if (error(obj1)=0) and obj1 NE _blank_ then
submit continue;
proc print data=&obj1;
run;
endsubmit;
else
_msg_='Nothing submitted. Please correct error.';
return;
Example 2: Generating a Compile Error with ERROR
The following sequence generates a compile error because the variable DS is not a
window variable but contains the name of a window variable. ERROR expects to be
passed the window variable itself.
ds='tablename';
if (error(ds)) then
do;
...SCL statements to handle the error condition...
end;
See Also
•
“DISPLAYED” on page 329
•
“ERROROFF” on page 353
•
“ERRORON” on page 354
•
“FIELD” on page 373
•
“MODIFIED” on page 545
ERROROFF
Clears the error flag on one or more FRAME entry controls or fields
Category:
Control or Field
Syntax
ERROROFF wvar-names |_ALL_;
Required Argument
wvar-names
specifies one or more window variables for which to turn off the error flag, or
_ALL_ to turn off the error flag for all window variables.
Type: Character
Details
An error flag can be set either by attributes that are assigned to fields or FRAME entry
controls, or by the ERRORON statement.
354
Chapter 13
•
SAS Component Language Dictionary
Use the following statement to clear the error flag for all FRAME entry controls or all
fields in the window:
erroroff _all_;
Statements in MAIN do not execute by default if a field is placed in error. Therefore, use
a CONTROL statement that specifies the ERROR option to enable ERROROFF to
remove the error flag.
The FRAME entry control or field cannot be an element of an array. To remove the error
flag for an array element, use FIELD instead.
FRAME entry controls can also use the _erroroff method.
Example
If a user enters an invalid value in the field TABLENAME, this SAS/AF program resets
the value of TABLENAME to the default and turns off the error flag. The field
TABLENAME is assigned type INPUT, so the procedure checks to see whether the SAS
table exists when a user enters a value for TABLENAME.
INIT:
control error;
return;
MAIN:
if (error(tablename)= 1) then
do;
tablename='my.default';
erroroff tablename;
end;
return;
See Also
•
“CONTROL” on page 274
•
“DISPLAYED” on page 329
•
“ERROR” on page 352
•
“ERRORON” on page 354
•
“FIELD” on page 373
ERRORON
Sets the error flag for one or more FRAME entry controls or fields
Category:
Control or Field
Syntax
ERRORON wcol-names |_ALL_;
ERRORON
355
Required Argument
wcol-names
specifies one or more window variables for which to turn on the error flag, or _ALL_
to turn the error flag on for all window variables.
Type: Character
Details
To set an error flag for multiple fields, specify the field names following ERRORON,
separated by blanks. To set an error flag for all fields in the window, use the following
statement:
erroron _all_;
To clear the error flag for one or more fields, use ERROROFF (see the preceding entry).
In SAS program entries, ERRORON causes the SCL program to execute when a user
presses any key the next time the window is displayed. Any fields for which the error
flag is set are marked as modified regardless of whether or not the user has changed the
value in the field.
In FSEDIT applications where a field is placed in error with ERRORON, a user can
enter a new value and the error status is removed from the field and reset if the error
condition is still met. In SAS/AF applications where a field is placed in error with
ERRORON, entering a valid value is not enough to remove the error flag. You must use
ERROROFF.
The FRAME entry control or field cannot be an element of an array. To set the error flag
for an array element, use FIELD instead.
FRAME entry controls can also use the _erroron method.
Example
Suppose your application manipulates a SAS table that contains information about
employees and the number of hours they work each week. Because only weekly
personnel are paid for overtime, the application should verify that all employees who
have reported overtime hours are weekly employees.
if (weekly='N' and overtime>0) then
do;
erroron overtime;
_msg_=
'Only weekly personnel can have overtime.';
return;
end;
See Also
•
“CONTROL” on page 274
•
“DISPLAYED” on page 329
•
“ERROR” on page 352
•
“ERROROFF” on page 353
•
“FIELD” on page 373
356
Chapter 13
•
SAS Component Language Dictionary
EVENT
Reports whether a pending event has occurred
Category:
Keys
Syntax
rc=EVENT();
Required Argument
rc
contains the return code for the operation:
1
a pending event has occurred.
0
a pending event has not occurred.
Type: Numeric
Details
EVENT is useful when you want your application to continue a task while it waits for
user input. For example, your application can read data from an external source and
display the results. When a user presses an appropriate key, you can stop processing and
handle the request.
An event can be a mouse button press or a keyboard key press. An event can also be
generated by a frame display or redisplay. Once a pending event has occurred, the
EVENT function returns 1 until the frame has been redisplayed.
A pending event can also be a system event that the user did not directly cause. For
example, the autosave feature, which is designed to save work in SAS at a specified
interval, generates an event that the EVENT function detects. To avoid accidentally
triggering the EVENT function, the autosave feature can be disabled through either the
SAS Preferences dialog box or the WAUTOSAVE OFF command. You can find the
autosave preference by selecting Tools ð Options ð Preferences... and the Edit tab.
Operating Environment Information
z/OSEVENT does not work under z/OS. On this system you should use the attention
handler exit that is provided in SCL. Refer to the discussion of the BREAK option
for “CONTROL” on page 274.
Example
Display the date and time until a user presses either ENTER or one of the function keys.
The variable DATETIME is a numeric text control on a frame entry and has the format
DATETIME17.2. When a user presses ENTER or a function key, the program exits the
loop and returns control to the application. In this example, when a user issues a RUN
command, the loop resumes.
INIT:
control allcmds;
_EVENT_
357
return;
MAIN:
if _status_ in ('C','E') then return;
if (word(1,'U')='RUN') then
do while(event()=0);
datetime.text=datetime();
refresh;
end;
return;
TERM:
return;
See Also
“CONTROL” on page 274
_EVENT_
Contains the type of event that occurred on a FRAME entry control
Category:
System Variable
Details
_EVENT_ is a character system variable. It is provided automatically by the FRAME
entry in SAS/AF, and the SCL compiler automatically creates a space for it in the SCL
data vector.
To use _EVENT_, you must use the DECLARE or LENGTH statement to declare it as a
character variable. If _EVENT_ is not declared, the following error is produced when
the _select or _objectLabel method executes:
ERROR: Expecting string (P), received SCL number
(symbol ’_EVENT_’).
_EVENT_ has a valid value only when a window control’s _select or _objectLabel
method is executing. _EVENT_ can have one of the following values:
‘ ‘ (blank)
Modification or selection
‘D’
Double click (An ’S’ select event always
precedes a ’D’ double click event.)
‘C’
Command
‘P’
Pop-up menu request
‘S’
Selection or single click
Example: Print the Event
The following _select method prints the value of _EVENT_ when a window control is
modified.
358
Chapter 13
•
SAS Component Language Dictionary
length _event_ $1;
SELECT: method;
call super(_self_,’_select’);
put _event_=;
endmethod;
See Also
•
“_METHOD_” on page 543
•
“_SELF_” on page 648
•
“_STATUS_” on page 678
•
“_VALUE_” on page 711
EXECCMD
Executes one or more commands when control returns to the application
Category:
Command
Syntax
CALL EXECCMD(cval);
Required Argument
cval
specifies one or more commands to execute. To specify multiple commands, place a
semicolon between each command.
Type: Character
Details
The commands are collected until another window is displayed or until SCL has finished
executing and control is returned to the procedure. The commands are then submitted to
the command-line processor before the next window is displayed or before the current
window is redisplayed.
The commands collected with EXECCMD will not be executed if the next window
displayed is a host window (such as CATLIST, DIRLIST, LIBLIST, FILELIST or
MESSAGEBOX). The commands will be held in a buffer until a non-host selector
window is displayed or the current window is redisplayed.
With CONTROL ALWAYS in FSEDIT applications or CONTROL ALLCMDS in other
SAS/AF applications, statements in MAIN execute before a command that is issued with
CALL EXECCMD. This behavior could introduce an infinite loop. Either execute the
EXECCMD routine conditionally or specify the command using EXECCMDI with the
NOEXEC parameter.
Example
Open the LIBNAME window and scroll down 5 items:
call execcmd('lib; down 5');
EXECCMDI
359
See Also
“EXECCMDI” on page 359
EXECCMDI
Executes one or more global commands immediately before processing the next statement, or executes
one non-global command when control returns to the application
Category:
Command
Syntax
CALL EXECCMDI(command<,when> );
Required Argument
command
specifies one or more commands to execute. To specify multiple commands, place a
semicolon between each command.
Type: Character
Optional Argument
when
specifies when the commands will be executed:
'EXEC'
executes commands in the command buffer immediately. (This is the default.)
'NOEXEC'
executes the specified non-global command when control returns to the
application. Global commands are still executed immediately.
Type: Character
Details
By default, the EXECCMDI routine immediately executes the specified global command
or list of global commands. After executing the command, the program statement that
immediately follows the call to EXECCMDI is executed. EXECCMDI is valid only in
SCL applications that display a window.
If you specify EXEC, which is the default for the when argument, then you should issue
only windowing environment global commands and full-screen global commands
through this routine. Any procedure-specific commands that are executed with
EXECCMDI are ignored.
An error is displayed on the message line if the string that is passed to EXECCMDI is
not a valid command, but the SCL program is not halted. Any statements that follow the
call to the routine are still executed. If multiple commands are specified and one is
invalid, none of the remaining commands are executed.
With the NOEXEC option, EXECCMDI allows only one procedure-specific or custom
command to be executed. EXECCMDI saves the command in the command buffer and
does not execute the command immediately. The program statement that immediately
360
Chapter 13
•
SAS Component Language Dictionary
follows the CALL EXECCMDI routine is executed. The command in the command
buffer is executed when control returns to the application.
If multiple EXECCMDI routines each have the NOEXEC option specified, then only the
command that was issued by the last EXECCMDI routine is executed. The previous
commands are cleared.
The NOEXEC option does not alter the way global commands are handled. Global
commands are still executed immediately.
With CONTROL ALWAYS in FSEDIT applications or CONTROL ALLCMDS in
SAS/AF applications, issuing EXECCMDI with the NOEXEC option from MAIN tells
SAS not to execute statements in MAIN again before executing the specified procedurespecific or custom command. This is different from issuing an EXECCMD routine from
MAIN, which would execute statements in MAIN again before executing the specified
command.
Note: We do not recommend combining EXECCMD and EXECCMDI routines,
because the order of execution may be unexpected.
Examples
Example 1: Using EXECCMDI to Ensure Correct Window Size
Ensure that the window is the correct size when the application runs:
INIT:
call execcmdi('zoom off');
return;
Example 2: Using EXECCMDI to Confirm a Delete Request
From an FSEDIT SCREEN entry, open CONFIRM.FRAME to confirm the delete
request before the row is actually deleted:
FSEINIT:
control always;
length confirm $ 3;
return;
INIT:
return;
MAIN:
if word(1, 'U') =: 'DEL' then
do;
call display('confirm.frame', confirm);
if confirm =
'YES' then call execcmdi('delete', 'noexec');
end;
return;
TERM:
return;
CONFIRM.FRAME contains two pushbutton controls, YES and NO, and is controlled
by the following program:
entry confirm $ 3;
YES:
confirm = 'YES';
_status_='H';
return;
EXIST
NO:
confirm = 'NO';
_status_='H';
return;
See Also
“EXECCMD” on page 358
EXIST
Verifies the existence of a member of a SAS data library
Category:
SAS Table
Syntax
rc=EXIST(member-name<,member-type<,generation> > );
Required Arguments
rc
contains the return code for the operation:
1
The library member exists.
0
Either member-name does not exist or member-type is invalid.
Type: Numeric
member-name
is the name of the SAS data library member.
Type: Character
Optional Arguments
member-type
is the type of SAS data library member:
'ACCESS'
indicates an access descriptor that was created using SAS/ACCESS software.
'AUDIT'
indicates the existence of an associated audit file.
'CATALOG'
indicates a SAS catalog or catalog entry.
'DATA'
indicates a SAS data file. (This is the default.)
'MDDB'
indicates an MDDB.
'VIEW'
indicates a SAS data view.
Type: Character
361
362
Chapter 13
•
SAS Component Language Dictionary
generation
is the generation number of the SAS table whose existence you are checking. If
member-type is not DATA, generation is ignored.
Type: Numeric
Details
If member-name is not specified, EXIST verifies the existence of the member specified
by the system variable _LAST_. If member-type contains an invalid value, EXIST
returns the value 0.
Examples
Example 1: Verifying the Existence of a SAS Table
Call the FSEDIT function only if the SAS table specified in the variable TABLENAME
exists. If the table does not exist, display a message on the message line.
if (exist(tablename)) then call fsedit(tablename);
else _msg_='Table '||tablename||' does not exist.';
Example 2: Verifying the Existence of a SAS Data View
Verify the existence of the SAS table view TEST.MYVIEW:
rc=exist('test.myview','view');
Example 3: Determining if a Data Set Generation Exists
Determine if the third generation of the data set work.one exists:
rc=exist('work.one','data',3);
Example 4: Querying for the Existence of an Audit Trail File
You can query for the existence of an audit trail file via the EXIST function. An audit
trail file is an optional SAS file that can be created to log changes to SAS data. To test
the EXIST function, follow these steps:
1. Create a data set with an audit file by entering the following code in the SAS Editor
and then submitting it:
data sasuser.class;
set sashelp.class;
run;
proc datasets lib=sasuser;
audit class;
initiate;
quit;
2. Test for the existence of the audit file by entering the following code in an SCL file:
INIT:
hasAudit=exist('sasuser.class','AUDIT');
put hasAudit=;
return;
When you compile and then execute the SCL code, the SAS log displays
'hasAudit=1', indicating that the audit file exists.
FAPPEND 363
3. Now delete SASUSER.CLASS and then recreated it without an audit file by entering
and then submitting in the SAS Editor the following DATA step:
data sasuser.class; set sashelp.class; run;
When you execute the SCL code from step 2 , the SAS log displays 'hasAudit=0'
(indicating that the audit file does not exist).
See Also
•
“CEXIST” on page 247
•
“FEXIST” on page 371
•
“FILEEXIST” on page 380
FAPPEND
Appends the current record to the end of an external file
Category:
External File
Syntax
sysrc=FAPPEND(file-id<,cc> );
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
file-id
contains the identifier that was assigned when the file was opened. If file-id is
invalid, the program halts.
Type: Numeric
Optional Argument
cc
specifies a carriage-control character:
blank
indicates that the record starts a new line.
'0'
skips one blank line before this new line.
'-'
skips two blank lines before this new line.
364
Chapter 13
•
SAS Component Language Dictionary
'1'
specifies that the line starts a new page.
'+'
specifies that the line overstrikes a previous line.
'P'
specifies that the line is a terminal prompt.
'='
specifies that the line contains carriage-control information.
all else
specifies that the record starts a new line.
Type: Character
Details
FAPPEND adds the record currently contained in the File Date Buffer (FDB) to the end
of an external file.
Operating Environment Information
z/OSRecords cannot be appended to partitioned data sets.
Example: Append a Record
Use FAPPEND to append a record to a file:
/* Assign the fileref THEFILE to the physical */
/* filename that the user entered in the
*/
/* field FNAME and open it in append mode.
*/
rc=filename( 'thefile',fname);
fid=fopen('thefile','a');
if (fid>0) then
do;
/* Append a new record to the file. */
rc=fput(fid,'Data for the new record');
rc=fappend(fid);
rc=fclose(fid);
end;
else
do;
...other SCL statements...
end;
rc=filename('thefile”,'');
See Also
•
“DOPEN” on page 333
•
“FGET” on page 372
•
“FOPEN” on page 401
•
“FPUT” on page 409
•
“FWRITE” on page 421
•
“MOPEN” on page 548
FCLOSE
365
FCLOSE
Closes an external file, a directory, or a directory member
Category:
External File
Syntax
sysrc=FCLOSE(file-id);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
file-id
contains the identifier that was assigned when the file was opened. A file-id value of
-999 closes all files opened with FOPEN. If file-id contains an invalid value, the
program halts.
Type: Numeric
Example
Close a file after manipulating it:
/* Assign the fileref THEFILE to the physical */
/* filename that is stored in the variable FNAME
/* and open it in append mode.
*/
rc=filename( 'thefile',fname);
fileid=fopen('thefile');
if (fileid>0) then
do;
rc=fread(fileid);
rc=fclose(fileid);
end;
else
do;
_msg_=sysmsg();
return;
end;
rc=filename('thefile','');
See Also
•
“DCLOSE” on page 302
•
“DOPEN” on page 333
•
“FOPEN” on page 401
*/
366
Chapter 13
•
SAS Component Language Dictionary
•
“MOPEN” on page 548
FCOL
Returns the current column position from the File Data Buffer (FDB)
Category:
External File
Syntax
col-num=FCOL(file-id);
Required Arguments
col-num
contains the current column position.
Type: Numeric
file-id
contains the identifier that was assigned when the file was opened. If file-id contains
an invalid value, the program halts.
Type: Numeric
Details
Use FCOL in conjunction with FPOS to move the pointer in the FDB and manipulate the
data.
Example
Use FCOL and FPOS to set the pointer in the FDB:
/* Assign the fileref THEFILE to the physical */
/* filename that the user entered in the field */
/* FNAME.
*/
rc=filename( 'thefile',fname);
fileid=fopen('thefile','o');
if (fileid>0) then do;
/* Put data into the FDB, get the
*/
/* current column, move the pointer
*/
/* by 1 and add more data to the FDB. */
record='This is data for the record';
rc=fread(fileid);
rc=fput(fileid,record);
pos=fcol(fileid);
rc=fpos(fileid,pos+1);
rc=fput(fileid,'and more data');
rc=fwrite(fileid);
rc=fclose(fileid);
end;
rc=filename('thefile','');
The record written to the external file is
FDELETE
367
This is data for the record and more data
See Also
•
“FPOS” on page 408
•
“FPUT” on page 409
•
“FWRITE” on page 421
FDELETE
Deletes an external file
Category:
External File
Syntax
sysrc=FDELETE(fileref);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
fileref
is the fileref that was assigned to the external file to be deleted. The fileref cannot be
associated with a list of concatenated filenames or directories. If the fileref is
associated with a directory, a PDS or a PDSE, then the directory, PDS, or PDSE
must be empty. You must have permission to be able to delete the file or directory.
Type: Character
Details
You can use either the FILENAME statement or the FILENAME function in SCL to
assign a fileref. Under some operating environments, you can also use system commands
to assign filerefs.
Example
Generate a fileref for an external file and assign it to the variable FREF. Then call
FDELETE to delete the file and call the FILENAME function again to deassign the
fileref.
length fref $ 8;
fref =_blank_;
/* Assign a fileref generated by the system */
/* to the physical filename that is stored */
/* in the variable FNAME.
*/
368
Chapter 13
•
SAS Component Language Dictionary
rc=filename(fref,fname);
if (rc=0) and (fexist(fref)) then
rc=fdelete(fref);
rc=filename(fref,'');
See Also
•
“FEXIST” on page 371
•
“FILENAME” on page 383
FETCH
Reads the next nondeleted row from a SAS table into the Table Data Vector (TDV)
Category:
SAS Table
Syntax
sysrc=FETCH(table-id<,'NOSET'> );
Required Arguments
sysrc
contains the return code for the operation:
0
successful
>0
not successful
<0
the operation was completed, but a warning or a note was generated. If the
row is locked, it is still fetched (read in) but a sysrc of _SWNOUPD is
returned.
−1
the end of the table was reached
Type: Numeric
table-id
is the identifier that was assigned when the table was opened. If table-id is invalid,
the program halts.
Type: Numeric
Optional Argument
'NOSET'
prevents the automatic passing of SAS table column values to SCL variables even if
the SET routine has been called.
Type: Numeric
Details
FETCH skips rows that have been marked for deletion. When a WHERE clause is
active, the function reads the next row that meets the WHERE condition.
FETCHOBS
369
If the SET routine has previously been called, the values for any table columns that are
also window variables or SCL variables for the application are automatically passed
from the TDV to the SCL Data Vector (SDV). To temporarily override this behavior so
that fetched values are not automatically copied to the SDV, use the NOSET option.
Example: Fetch a Row
Fetch the next row from the SAS table MYDATA. If the end of the table is reached or if
an error occurs, SYSMSG retrieves the appropriate message and displays it on the
message line.
INIT:
tableid=open('mydata','i');
return;
MAIN:
rc=fetch(tableid);
if rc then _msg_=sysmsg();
else
do;
...more SCL statements...
end;
return;
TERM:
rc=close(tableid);
return;
See Also
•
“APPEND” on page 217
•
“FETCHOBS” on page 369
•
“GETVARC and GETVARN” on page 433
•
“LOCATEC and LOCATEN” on page 519
•
“PUTVARC and PUTVARN” on page 609
•
“SET” on page 651
•
“UPDATE” on page 705
FETCHOBS
Reads a specified row from a SAS table into the Table Data Vector (TDV)
Category:
SAS Table
Syntax
sysrc=FETCHOBS(table-id,row-number<,options> );
Required Arguments
sysrc
contains the return code for the operation:
370
Chapter 13
•
SAS Component Language Dictionary
0
successful
>0
not successful
<0
the operation was completed, but a warning or a note was generated. If the
row is locked, it is still fetched (read in) but a sysrc of _SWNOUPD is
returned.
−1
the end of the table was reached
Type: Numeric
table-id
is the identifier that was assigned when the table was opened. If table-id is invalid,
the program halts.
Type: Numeric
row-number
is the number of the row to read.
Type: Numeric
Optional Argument
options
is one or both of the following options, separated by blanks:
'ABS'
specifies that the value of row-number is absolute; that is, deleted rows are
counted.
'NOSET'
prevents the automatic passing of SAS table column values to SCL variables
even if the SET routine has been called.
Type: Character
Details
If SET has previously been called, the values for any table columns that are also window
variables or SCL variables for the application are automatically passed from the TDV to
the SCL Data Vector (SDV) with FETCHOBS. You can use NOSET in the FETCHOBS
function to temporarily override this behavior so that fetched values are not
automatically copied to the SDV. FETCHOBS treats the row value as a relative row
number unless the ABS option is specified.
The row value may or may not coincide with the physical row number on disk. For
example, the function skips rows that have been marked for deletion. When a WHERE
clause is active, the function counts only rows that meet the WHERE condition. If rownumber is less than 0, the function returns an error condition. If row-number is greater
than the number of rows in the SAS table, an 'End of file' warning is returned.
Example: Fetch a Specific Row
Fetch the tenth row from the SAS table MYDATA. If the end of the table is reached, a
message to that effect is displayed on the message line. If an error occurs, the SYSMSG
function retrieves the error message and displays it on the message line.
rc=fetchobs(mydata,10);
if (rc=-1) then
FEXIST
371
_msg_='End of table has been reached.';
if (rc ne 0) then _msg_=sysmsg();
See Also
•
“APPEND” on page 217
•
“FETCH” on page 368
•
“GETVARC and GETVARN” on page 433
•
“LOCATEC and LOCATEN” on page 519
•
“PUTVARC and PUTVARN” on page 609
•
“SET” on page 651
•
“UPDATE” on page 705
FEXIST
Verifies the existence of the external file that is associated with the specified fileref
Category:
External File
Syntax
rc=FEXIST(fileref);
Required Arguments
rc
contains the return code for the operation:
1
successful
0
not successful, or there was no logical assignment for the fileref
Type: Numeric
fileref
is the fileref that was assigned to the external file.
Type: Character
Details
You can use either the FILENAME statement or the FILENAME function in SCL to
assign filerefs. Under some operating systems, you can also use system commands to
assign filerefs. Use FILEEXIST to verify the existence of a file based on its physical
name.
Example: Verify a File
Verify the existence of an external file for a fileref that the user enters in the field for the
window variable FREF. A message informs the user whether the file exists.
if (fexist(fref)) then
372
Chapter 13
•
SAS Component Language Dictionary
_msg_=
'The file does exist.';
else
_msg_=sysmsg();
See Also
•
“EXIST” on page 361
•
“FILEEXIST” on page 380
•
“FILENAME” on page 383
•
“FILEREF” on page 386
•
“PATHNAME” on page 584
FGET
Copies data from the File Data Buffer (FDB)
Category:
External File
Syntax
sysrc=FGET(file-id,cval<,length> );
Required Arguments
rc
contains the return code for the operation:
0
successful
−1
the end of the FDB was reached, or no more tokens were available.
Type: Numeric
file-id
is the identifier that was assigned when the file was opened. If file-id is invalid, the
program halts.
Type: Numeric
cval
is a character variable to hold the data.
Type: Character
Note
This parameter is an update parameter. See “Input, Output, and Update
Parameters” on page 38 for more information.
Optional Argument
length
specifies how many characters to retrieve from the FDB.
Type: Numeric
FIELD
373
Details
FGET copies data from the FDB into a character variable. If length is specified, then
only the specified number of characters is retrieved (or the number of characters
remaining in the buffer, if that number is less). If length is omitted, then all characters in
the FDB from the current column position to the next delimiter are returned. The default
delimiter is a blank. The delimiter is not retrieved. (See “FSEP” on page 416 for more
information about delimiters.)
After FGET is executed, the column pointer is automatically moved to the next “read”
position in the FDB.
Example: Copy a Record
Read the first record in the file specified by the user and copy the first token into the
variable THESTRING.
/* Assign the fileref THEFILE to the physical
/* filename that is stored in the
*/
/* variable FNAME and open it in append mode.
rc=filename( 'thefile',fname);
fileid=fopen('thefile');
if (fileid>0) then
do;
/* Read the first record, retrieve the
/* first token of the record and store
/* it in the variable THESTRING.
rc=fread(fileid);
rc=fget(fileid,thestring);
put thestring;
rc=fclose(fileid);
end;
rc=filename('thefile','');
*/
*/
*/
*/
*/
See Also
•
“FPOS” on page 408
•
“FREAD” on page 411
•
“FSEP” on page 416
FIELD
Performs an action on or reports the state of FRAME entry widgets or fields
Category:
Widget or Field
Syntax
rc=FIELD(action<,wvar-name-1<,wvar-name-2<,wvar-name-3> > > );
374
Chapter 13
•
SAS Component Language Dictionary
Required Arguments
rc
contains the return code for the operation. The return value is dependent on the
action.
Type: Numeric
action
is an action from the list of actions, described below.
Type: Character
Optional Argument
wvar-name-1, wvar-name-2, wvar-name-3
are character columns or expressions whose values are the names of one or more
FRAME entry widgets or fields in a window, separated by spaces. At least one name
is required for all actions except ALARM, BLOCKCUROFF, BLOCKCURON,
CURSCREEN, HOME, NSCREEN, and SMOOTHSCRL.
Type: Character
Details
The FIELD function combines the functionality of the field statements (CURSOR,
DISPLAYED, ERROROFF, ERRORON, PROTECT, and so on). At least one window
column name is required for all actions except ALARM, BLOCKCUROFF,
BLOCKCURON, CURSCREEN, HOME, NSCREEN, and SMOOTHSCRL.
Values for the action Argument
The following list contains the values that you can specify for action. The list also
includes the corresponding methods that can be used in FRAME entries, which are
documented with FRAME entry classes in the online Help for SAS/AF software.
'ALARM'
sounds a bell. This action has a corresponding SCL statement.
'BLOCKCUROFF'
turns the block cursor off so that fields or text entry widgets are not highlighted when
a user tabs or moves the cursor to them.
'BLOCKCURON'
turns the block cursor on, which causes input fields to be highlighted when the cursor
is on the text entry widget or field.
'COLOR color <attribute>'
changes the color and display attribute of a field, text entry widget, or text label
widget in the window. Colors are: BLACK, BLUE, BROWN, CYAN, GRAY,
GREEN, MAGENTA, ORANGE, PINK, RED, WHITE, and YELLOW. Attributes
are: NONE, BLINKING, HIGHLIGHT, HIREV, REVERSE, and UNDERLINE.
SASCOLOR window elements can be used for color. If you specify a SASCOLOR
window element for color, then attribute is not allowed, because the SASCOLOR
window element already contains a display attribute.
'COLUMN'
returns the column where a FRAME entry widget or field is located. This option is
valid only in SAS/AF software. FRAME entry widgets can also use the _column
method.
FIELD
375
'CUROBS'
returns the current row number for FSEDIT and FSVIEW for the specified field.
'CURSOR'
positions the cursor in the FRAME entry widget or field. If more than one field or
widget is specified, the cursor is positioned in the last one specified. This action has
a corresponding SCL statement. FRAME entry widgets can also use the _cursor
method.
'CURSCREEN'
returns the current screen number. For SAS/AF software, this is valid only for
multipage PROGRAM entries. For FSEDIT, it reports which screen of a multiscreen
application is displayed.
'DISPLAYED'
returns the total number of FRAME entry widgets or fields that are visible, or 0 if
none of them are currently displayed. For example, if you pass three field names and
two are visible, then rc is 2. This action has a corresponding SCL function. FRAME
entry widgets can also use the _isDisplayed and _isHidden methods.
'ERROR'
returns the total number of FRAME entry widgets or fields that are in error, or 0 if
none of the specified fields are in error. For example, if you pass two field names
and one is in error, then rc is 1. This action has a corresponding SCL function.
FRAME entry widgets can also use the _inError method.
'ERROROFF'
removes the error status from one or more FRAME entry widgets or fields. This
action has a corresponding SCL statement. FRAME entry widgets can also use the
_erroroff method.
'ERRORON'
turns on the error status for one or more FRAME entry widgets or fields. Turning on
the error status prevents users from ending the SAS/AF application or from leaving
the current row in FSEDIT. The error status also highlights the field or widget, using
the error color and display attributes that were assigned in the Attribute (or ATTR)
window. This action has a corresponding SCL statement. FRAME entry widgets can
also use the _erroron method.
'GETOBS'
reports whether a formula is being executed in an FSVIEW application because a
column is being read. If rc is 1, then the formula is being executed because a column
is being read. If rc is 0, then the formula is being executed because a column has
been modified. If you are on a new row, rc is always 1. This is the opposite of
PUTOBS.
'HOME'
moves the cursor to the command line. This entry has a corresponding SCL
statement.
'ICON icon-number'
assigns a number for an icon that represents the field if it is a pushbutton in
PROGRAM entries. This option is valid only in SAS/AF software. FRAME entry
widgets can use the _setIcon method.
'MODIFIED'
returns the total number of FRAME entry widgets or fields that were modified, or 0
if none of them were modified. For example, if you pass two field names and both
were modified, then rc is 2. This action has a corresponding SCL function. FRAME
entry widgets can also use the _isModified method.
376
Chapter 13
•
SAS Component Language Dictionary
'NSCREEN'
returns the number of screens (for FSEDIT applications) or the number of panes (for
SAS/AF applications).
'PROTECT'
protects one or more FRAME entry widgets or fields. This prevents a user from
modifying the FRAME entry widget or field. This action has a corresponding SCL
statement. FRAME entry widgets can also use the _protect method.
'PROTECTED'
reports whether a FRAME entry widget or field is protected. FRAME entry widgets
can also use the _isProtected method.
'PUTOBS'
reports whether a formula is being executed in an FSVIEW application because a
column has been modified. If rc is 1, then the formula is being executed because a
column has been modified. If rc is 0, then the formula is being executed to read a
column. If you are on a new row, rc is always 0. This is the opposite of GETOBS.
'ROW'
returns the row where a FRAME entry widget or field is positioned. This option is
valid only in SAS/AF software. FRAME entry widgets can also use the _row
method.
'SMOOTHSCRL'
sets smooth scrolling to ON, OFF, or TOGGLE. Allows smooth scrolling when users
drag the thumb in the scroll bar. When smooth scrolling is on, the getrow sections of
AF extended tables are called while the thumb is dragged. In the FSVIEW
procedure, the display is refreshed while the thumb is dragged. When smooth
scrolling is turned off, the redisplay is deferred until the thumb is released. By
default, smooth scrolling is off for SAS/AF and on for FSVIEW.
If you do not specify ON or OFF, SMOOTHSCRL is toggled from OFF to ON or
from ON to OFF.
'UNPROTECT'
unprotects one or more fields or FRAME entry widgets. This enables a user to
modify the field or FRAME entry widget. This action has a corresponding SCL
statement. FRAME entry widgets can also use the _unprotect method.
Examples
Example 1: Using FIELD to Allow Smooth Scrolling
Allow smooth scrolling:
rc=field ('smoothscr1', 'on');
Example 2: Using FIELD to Check for Error Status of Fields
Create the array FLDNAMES and pass its elements to the FIELD function to check the
error status of the fields. If necessary, move the cursor to the field that contains invalid
data.
array fldnames{*} $ 8 ('tablename','colname','list',
'x','y');
do i=1 to dim(fldnames);
if (field('error',fldnames{i})) then
do;
_msg_='Field name '||
FILEDIALOG
377
fldnames{i}||' is bad.';
rc=field('cursor',fldnames{i});
return;
end;
end;
Example 3: Using FIELD to Turn on an Error Flag
Turn on the error flag for FIELD1 and FIELD2:
rc=field('erroron','field1','field2');
Example 4: Using FIELD to Change a Field's Color
Change the color of FIELD1:
rc=field('color blue','FIELD1');
Example 5: Using FIELD to Change Color and Display Attributes for
a Field
Change FIELD1's color and display attributes:
rc=field('color red reverse','field1');
Example 6: Using FIELD to Specify a SASCOLOR Window Element
Specify FIELD1's color, using the name of a SASCOLOR window element:
rc=field('color foreground','field1');
See Also
•
“ALARM ” on page 217
•
“CURSOR” on page 296
•
“DISPLAYED” on page 329
•
“ERROR” on page 352
•
“ERROROFF” on page 353
•
“ERRORON” on page 354
•
“HOME” on page 444
•
“MODIFIED” on page 545
•
“PROTECT” on page 602
•
“UNPROTECT” on page 703
FILEDIALOG
Displays a selection window that lists external files
Category:
External File
378
Chapter 13
•
SAS Component Language Dictionary
Syntax
rc=FILEDIALOG(dialog-type, filename
<,default-file >
<,default-dir>
<,filter-1. . . ,filter-11>
<,description-1 . . .<description-11> >);
Required Arguments
rc
contains the return code for the operation:
−1
A user canceled without selecting a file.
0
Either dialog-type is OPEN and the file exists, or dialog-type is SAVEAS
and the file does not exist.
1
Dialog-type is SAVEAS or SAVEASNOAPPEND, the file exists, and the user
wants to replace the file.
2
Dialog-type is SAVEAS, the file exists, and a user wants to append to the
file.
Type: Numeric
dialog-type
specifies the type of dialog window to open. An invalid type specification produces
an error and halts the program. Types are
'AGGREGATE'
lists aggregate storage areas — for example, directories, partitioned data sets, or
MACLIBs.
'LIBRARY'
lists SAS data libraries.
'OPEN'
lists files that a user can open.
'SAVEAS'
lists files that a user can write to.
'SAVEASNOAPPEND'
lists files that a user can write to but the append option is not allowed.
Type: Character
filename
is the fully qualified name of the selected file, including the directory.
Type: Character
Note
This parameter is an update parameter. See “Input, Output, and Update
Parameters” on page 38 for more information.
FILEDIALOG
379
Optional Arguments
default-file
is the name of the file (without directory information) to display as selected when the
dialog window opens. If you specify a null string (''), the file that was selected last
is the default file.
Type: Character
default-dir
is the directory whose files are listed when the dialog window opens. If you specify a
null string (''), the directory that was selected last is the default directory.
Type: Character
filter1 ... filter11
are up to 11 name specifications to narrow the list of files to display — for example,
*.html. The number of filter arguments is host specific. If you do not supply a filter,
the list contains all files in default-dir.
Type: Character
description1 ... description11
are up to 11 descriptions, one for each filter, to make the dialog window more
informative for application users. If no descriptions are supplied, a default
description is displayed for each specified filter. If you provide a description for any
filter, then you must supply a description for each filter that you specify.
Type: Character
Details
Depending on the values of default-dir and filter, default-file may not be in the list of
files displayed. Therefore, default-file will not be selected.
An error condition is produced if you supply a description for at least one filter but fail
to supply a description for each specified filter.
Operating Environment Information
The formats of the files and filter parameters are all host specific. The UNIX and
Microsoft Windows platforms use all of the passed filters. The Macintosh platform
ignores the filter argument. All other platforms use only the first filter that is passed.
Examples
Example 1: Select a File to Open
Enable a user to select a file to open, and see whether the user canceled the window:
rc=filedialog('saveas',selfile,'autoexec.sas',
'/sas','*.sas');
/* Process the selected file */
select(rc);
when(0) put 'New file selected';
when(1) put 'REPLACE an existing file';
when(2) put 'APPEND to an existing file';
when(-1) put 'User pressed cancel';
otherwise put 'ERROR occurred';
end;
380
Chapter 13
•
SAS Component Language Dictionary
Example 2: Display Filenames
Display a list of filenames that have .SAS, .HTML, and .GIF extensions, and provide
descriptions for these filters:
rc=filedialog('open',selfile,'','',
'*.sas','*.html','*.gif','','','','','','','','',
'SAS Files','Web Pages','Images');
See Also
“FILELIST” on page 381
FILEEXIST
Verifies the existence of an external file, a directory, or a SAS data library by its physical name
Category:
External File
Syntax
sysrc=FILEEXIST(filename);
Required Arguments
rc
contains the return code for the operation:
1
The external file exists.
0
The external file does not exist.
Type: Numeric
filename
is the name that identifies the external file to the host operating system. The filename
specification varies according to the operating system.
Type: Character
Details
FILEEXIST verifies the existence of an external file, a directory, or a SAS data library.
Although your system utilities may recognize partial physical filenames, you must
always use fully qualified physical filenames with FILEEXIST.
Example: Verify a File
Verify the existence of an external file whose filename the user enters in the field for the
window variable FNAME. Display a message on the message line to tell the user
whether the file exists.
if (fileexist(fname)) then
_msg_='The external file '||fname||' exists.';
else
_msg_=sysmsg();
FILELIST 381
See Also
•
“EXIST” on page 361
•
“FEXIST” on page 371
•
“FILENAME” on page 383
•
“FILEREF” on page 386
•
“PATHNAME” on page 584
FILELIST
Displays a host selection window that lists the currently assigned filerefs, and returns user selections
Category:
Selection List
Syntax
selections=FILELIST(<sel-excl<,message<,autoclose <,num-sel> > > > );
Required Argument
selections
contains the user's selections, or a blank if no fileref was selected. Multiple selections
are separated by blanks. By default, selections is 200 bytes long. To accommodate
values longer than 200 bytes, explicitly declare selections with a longer length.
Type: Character
Optional Arguments
sel-excl
specifies which filerefs to include in the selection window. Specify as
•
one or more filerefs that have been assigned for the current SAS session. Use
spaces to separate multiple filerefs.
•
an asterisk ('*') or a null string ('') to display all the filerefs that are defined
for the current SAS session.
•
a NOT sign (¬ or ^) followed by one or more filerefs, to display all filerefs
except those listed after the NOT sign. For example, '^ MYFILE1 MYFILE2'
displays all defined filerefs except MYFILE1 and MYFILE2.
Type: Character
message
is the text for a message to display above the selection list. The default message tells
users to make up to the number of selections specified in num-sel.
Type: Character
autoclose
is an obsolete argument but is retained for compatibility with earlier releases. If you
want to specify a value for num-sel, then specify ” as a placeholder for this
argument.
Type: Character
382
Chapter 13
•
SAS Component Language Dictionary
num-sel
is the maximum number of items a user can select from the list. To display the list
for information purposes only (no selections allowed), specify 0. To specify an
unlimited number of selections, use a value such as 9999 that is larger than the
number of available selections. A user cannot make a number of selections that
exceeds the number of items in the list.
Type: Numeric
Details
The selection list displays both filerefs and the corresponding physical names of the
external files to which the filerefs are assigned, but only the selected fileref is returned.
If you omit all the arguments for FILELIST (for example,
selections=filelist();), the selection list window contains all filerefs that have
been assigned in the current SAS session.
You can provide default values that will be initially selected when the fileref selection
list is displayed. To do this, assign the values to the selections variable before calling
FILELIST.
If a user closes the selection list window without making a selection, FILELIST returns a
blank value unless there was an initial value for the selections variable before FILELIST
was called.
Selections from the window can be returned in the current result list, if one is available.
The current result list is a special SCL list that is automatically filled with the values that
are selected from a selection list. To use a current result list, use the MAKELIST
function to create the list, and use the CURLIST function to designate it as the current
result list. The current result list must exist before you call the FILELIST function.
When FILELIST is invoked, the current result list is cleared. After FILELIST is
invoked, the current result list contains the following named items:
TAG
identifies the list as one that was created by FILELIST.
Type: Character
COUNT
contains the number of selected filerefs, or 0 if a user makes no selections or issues a
CANCEL command in the list window.
Type: Numeric
FILEREF
contains the name of each selected fileref. There is a FILEREF element for each
selected fileref.
Type: Character
FILENAME
contains the physical name of the external file for each selected fileref. There is a
FILENAME element for each selection made.
Type: Character
Because some engines support mixed-case filenames, FILELIST now retains the cases
of the returned selected items. This may cause your application to fail if your application
contains code that assumes the returned selection is uppercased. For example,
if (filelist(dsid, 'TESTNDX')='NDXVAR')
must be changed to
FILENAME
383
if (upcase(filelist(dsid, 'TESTNDX'))='NDXVAR'
If the application cannot be modified, you may need to specify the
VALIDVARNAME=V6 system option when you run the application to ensure that the
selections returned from the FILELIST function will be uppercased.
Examples
Example 1: Displaying Specified Filerefs
Open a window that displays a list of all defined filerefs except for LISTNUM.
select=filelist('^listnum');
Example 2: Using a Current Result List for Multiple User Selections
Open a window that displays a list of all defined filerefs except LISTNUM. Users can
make up to five selections. The selections are retrieved from the current result list.
listid=makelist();
rc=curlist(listid);
select=filelist('^listnum',' ',' ',5);
n=getnitemn(listid,'COUNT');
do i=1 to n;
fileref=getnitemc(listid,'FILEREF',i);
physname=getnitemc(listid,'FILENAME',i);
put fileref= physname=;
end;
See Also
•
“CATLIST” on page 240
•
“DIRLIST” on page 323
•
“LIBLIST” on page 504
FILENAME
Assigns or deassigns a fileref for an external file, a directory, an output device, or a catalog entry
Category:
External File
Syntax
sysrc=FILENAME(fileref,filename<,device <,host-options<,dir-ref> > > );
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
384
Chapter 13
•
SAS Component Language Dictionary
fileref
is the fileref to assign. A blank fileref ('') causes an error condition. If the fileref is
an SCL character variable that has a blank value, a fileref will be generated for you.
Type: Character
filename
is the physical name of an external file.
Type: Character
Optional Arguments
device
is the type of device if the fileref points to something other than a physical file:
CATALOG
a catalog entry
DUMMY
output to the file is discarded
FTP
the file transfer protocol (FTP) access method
GTERM
graphics on the user's terminal
NAMEPIPE
a named pipe.
Note: Some operating systems do not support pipes.
PIPE
an unnamed pipe
Note: Some operating systems do not support pipes.
PLOTTER
an unbuffered graphics output device
PRINTER
a printer or printer spool file
SOCKET
the Transmission Control Protocol/Internet Protocol (TCP/IP) socket access
method
TERMINAL
the user's terminal
TAPE
a tape drive
URL
the URL access method
Type: Character
host-options
are host-specific details such as file attributes and processing attributes. Host-options
can also be used to specify device options. For example, they could include output
destinations, and CATALOG, FTP, URL, TCPIP, and SOCKET options. For details
about host and device options, see the “FILENAME Statement” in SAS Statements:
Reference and the SAS documentation for your operating environment.
FILENAME
385
Type: Character
dir-ref
is the fileref assigned to the directory or partitioned data set in which the external file
resides.
Type: Character
Details
The name associated with the file or device is called a fileref (file reference name). Other
SCL functions that manipulate external files and directories require that the files be
identified by a fileref rather than by a physical filename. A system-generated fileref is
not displayed in the FILENAME window.
The association between a fileref and a physical file lasts only for the duration of the
current SAS session or until you use FILENAME to change or discontinue the
association. If you specified the RECONN option when the fileref was assigned, then
you must specify the CLEAR option to deassign the fileref. You can deassign other
filerefs by specifying a null string for the filename argument.
Operating Environment Information
The term directory in this description refers to an aggregate grouping of files that are
managed by the host operating system. Different host operating systems identify
such groupings with different names, such as directory, subdirectory, MACLIB, or
partitioned data set. See the SAS documentation for your operating environment for
details. Under some operating systems, you can also use system commands to assign
filerefs. Depending on the operating system, FILENAME may be unable to change
or de-assign filerefs that are assigned outside of a SAS session. See the SAS
documentation for your operating environment for information about the systemdependent options that you can specify for options.
Examples
Example 1: Assigning a Fileref
Assign the fileref MYFILE to an external file:
/* Assign fileref MYFILE to the physical */
/* filename stored in the variable FNAME
*/
rc=filename('myfile',fname);
if (rc ne 0) then
_msg_=sysmsg();
Example 2: Using a System-Generated Fileref
Assign a system-generated fileref, stored in the variable FNAME, to the file whose
physical name is in the control FNAME:
fname=' ';
/* Assign a system-generated fileref to the */
/* filename stored in the variable FNAME
*/
rc=filename(fname,fname);
if (rc) then
_msg_=sysmsg();
else
do;
...more SCL statements...
end;
386
Chapter 13
•
SAS Component Language Dictionary
/* De-assign the fileref */
rc=filename('myfile','');
Example 3: Making an External File Accessible to a Client
Assign a fileref to an external file:
rc=filename('sharedfl','\ABC\XYZ\AUTOEXEC.SAS);
Example 4: Assigning a Fileref for a Pipe File
Assign a fileref for a pipe file with the output from the UNIX command LS, which lists
the files in the directory /u/myid:
rc=filename('myfile','ls /u/myid','pipe');
See Also
•
“FEXIST” on page 371
•
“FILEEXIST” on page 380
•
“FILEREF” on page 386
•
“PATHNAME” on page 584
FILEREF
Verifies that a fileref has been assigned for the current SAS session or process
Category:
External File
Syntax
sysrc=FILEREF(fileref);
Required Arguments
sysrc
contains the return code for the operation:
0
Both the fileref and the external file exist.
<0
The fileref has been assigned, but the file that it points to does not exist.
>0
The fileref has not been assigned.
Type: Numeric
fileref
is the fileref to be validated (up to eight characters).
Type: Character
Details
A negative return code indicates that the fileref exists but that the physical file associated
with the fileref does not exist. A positive, nonzero value indicates that the fileref has not
been assigned.
FILLIST 387
A fileref can be assigned to an external file by using the FILENAME statement or the
FILENAME function in SCL. Under some operating systems, you can also use system
commands to assign filerefs. See the SAS documentation for your operating
environment.
Examples
Example 1: Determining Whether a Fileref Has Been Assigned to an
External File
Test whether the fileref MYFILE is currently assigned to an external file. A system error
message is issued if the fileref is not currently assigned.
if (fileref('myfile') > 0) then _msg_=sysmsg();
Example 2: Determining Whether a Fileref and Its File Exist
Test the fileref MYFILE to determine whether the fileref is assigned and whether the file
that it refers to exists:
if (fileref('myfile') ne 0) then _msg_=sysmsg();
See Also
•
“FEXIST” on page 371
•
“FILEEXIST” on page 380
•
“FILENAME” on page 383
•
“PATHNAME” on page 584
FILLIST
Fills an SCL list with text and data
Category:
List
Syntax
sysrc=FILLIST(type,source,list-id<,attr-list-id<,desc-var-name> > );
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
type
specifies the type of file or data source named in source and one or more options to
use:
388
Chapter 13
•
SAS Component Language Dictionary
'CATALOG<(options)>'
specifies that source names a catalog entry.
'FILE<(options)>'
specifies that source names an external file.
'FILEREF<(options)>'
specifies that source names a fileref that has been assigned to an external file.
'SASICONS<(numbers)>'
specifies the numbers for icons that are provided with SAS software. (When you
specify SASICONS, source is ignored. Specify a null argument '' for source.)
'SEARCH'
specifies catalog names in the current search path (source is ignored). Use the
SEARCH function to define the search path, or specify '' for source.
Type: Character
source
is a catalog entry (specified as libref.catalog.entry.type), an external file, or a fileref.
Type: Character
list-id
contains the identifier of the list to fill. An invalid list-id produces an error condition.
Type: Numeric or List
Optional Arguments
attr-list-id
contains the identifier of the list to fill with text attribute source information when
type is CATALOG and the entry type is LOG, OUTPUT, or SOURCE. An invalid
attr-list-id produces an error condition.
Type: Numeric
desc-var-name
is the name of the variable in which you want to store the text of the catalog entry
description. This argument is ignored if type is FILE or FILEREF.
Type: Character
The available options are described in “Type Options” on page 388. Separate
multiple options with blanks. For example, to fill a list from an external print file and
to strip carriage-control characters, specify FILE(PRINT STRIPCC) for type.
Note
This parameter is an update parameter. See “Input, Output, and Update
Parameters” on page 38 for more information.
Details
Type Options
ADDCC
adds default host carriage-control characters. Used with type FILE, FILEREF, and
CATALOG and with catalog entry types LOG, OUTPUT, and SOURCE.
PRINT
designates an external file as a PRINT file (uses the host carriage-control characters).
Used with type FILE and FILEREF.
FILLIST 389
STRIPCC
removes carriage-control characters. Used with type FILE, FILEREF, and CATALOG
and with catalog entry types LOG, OUTPUT, and SOURCE.
TRIM
trims trailing blanks. Used with type FILE, FILEREF and CATALOG and with
catalog entry types LOG, OUTPUT, and SOURCE. TRIM is used if you want to use
FILLIST to fill a list with items that contain trailing blanks and then remove the
blanks so that they will not be displayed in a pop-up menu that is produced by
POPMENU.
List Creation
Each line of text in the source file is placed in a separate character item of the list
identified by list-id. The number of items in the filled list is determined by the number of
lines of text. All SCL lists must be created with MAKELIST before you call FILLIST.
FILLIST automatically clears the lists before it fills the lists.
Data from the external file or catalog entry cannot exceed the maximum length of a
character value in an SCL list item, which is 32,766 characters.
External Files
If type is FILE, then source is the name of an external file. If type is FILEREF, then
source is a SAS fileref. FILLIST reads each record of the file into a separate character
item.
SLIST Catalog Entries
If type is CATALOG and the catalog entry type in source is SLIST, then the types of the
items in the filled list are determined by the saved list, and they may be character strings,
numbers, or other lists. All item attributes and names are duplicated, as are the list
attributes. However, the list identifier numbers are different.
LIST Catalog Entries
If type is CATALOG and the catalog entry type in source is LIST, FILLIST reads the
contents of a SAS/AF LIST entry into list-id. The list contains either all numeric or all
character items, depending on the contents of the LIST entry. The attribute list contains
the following named values, which are all character type:
INFORMAT
is the SAS informat that was specified in the LIST entry.
FORMAT
is the SAS format that was specified in the LIST entry.
MESSAGE
is the error message that was specified in the LIST entry.
CAPS
reports whether the LIST entry has the CAPS attribute. Y or N.
SORTED
reports whether the LIST entry has the SORT attribute. Y or N.
NOHONORCASE
reports whether the LIST entry has the CASE-INSENSITIVE attribute. Y or N.
TYPE
is the TYPE attribute that was specified in the LIST entry. N for numeric, C for
character.
390
Chapter 13
•
SAS Component Language Dictionary
JUST
is the JUST attribute that was specified in the LIST entry. L, R, C, or N for left, right,
center, or none.
SOURCE, OUTPUT, and LOG Catalog Entries
If type is CATALOG and the entry type is OUTPUT, LOG, or SOURCE, the first character
in each list item contains a FORTRAN carriage-control character: 1 means that a new
page starts with this line. See STRIPCC above. ADDCC converts all carriage-control
characters to ' ' (blank).
If type is CATALOG and the entry type is OUTPUT, LOG, or SOURCE, then any text
attributes (such as color and display attributes), are read one element per line into attrlist-id, if it is specified. These attributes consist of a character item for each line of text.
Each character item contains one character for each character in the line, plus a prefix
descriptor character. The prefix character is T for a title line, H for a header line, or D for
a data line. The other characters represent the text display attributes and color, as
described in the tables below.
Do not confuse text attributes (color, display, and so on) with list attributes that are
specified with SETLATTR.
The attribute list that is filled by FILLIST contains one item for each line of text from
the SAS catalog entry. The attribute string for each line has one character for each
character of text. Each attribute character represents the SAS windowing environment
color and display attribute. Not all display devices support all colors.
Table 13.2
Color Attributes Representation
Color
Value
Color
Value
BLUE
'10'x
WHITE
'70'x
RED
'20'x
ORANGE
'80'x
PINK
'30'x
BLACK
'90'x
GREEN
'40'x
MAGENTA
'A0'x
CYAN
'50'x
GRAY
'B0'x
YELLOW
'60'x
BROWN
'C0'x
Table 13.3
Display Attributes Representation
Attribute
Value
NONE
'00'x
HIGHLIGHT
'01'x
UNDERLINE
'02'x
BLINK
'04'x
FILLIST 391
Attribute
Value
REVERSE
'08'x
You combine the color and display attributes by adding them together. For example, you
can specify GREEN UNDERLINE by adding '40'x to '02'x to yield '42'x. To assign
GREEN UNDERLINE to the first 4 characters of a string, you could use a statement
like:
str = '42424242'x;
See also “STRATTR” on page 681 , which creates attribute strings.
You can use GETITEMC or POPC to retrieve an item from this list.
An error condition is produced if
•
either list has the NOUPDATE, NUMONLY, or FIXEDLENGTH attribute
•
any item in either list cannot be removed because it has the NODELETE attribute.
Examples
Example 1: Reading Text and Attributes Into a List
Suppose you have an OUTPUT entry named
FINANCE.REPORTS.MONTHLY.OUTPUT that contains the text "Net:($45,034)" on
line 45. The text Net: is white with no highlight attributes, whereas the text
($45,034) is red reverse. The following statements read the text and attributes and
print line 45.
INIT:
text_list=makelist();
attr_list=makelist();
rc=fillist('CATALOG',
'FINANCE.REPORTS.MONTHLY.OUTPUT',
text_list,attr_list);
text=substr(getitemc(text_list,45),2);
attr=substr(getitemc(attr_list,45),2);
len=compress(put(2*length(text), 4.));
attrhex=putc(attr,'$HEX'||len||'.');
put attr;
put text;
put attrhex;
return;
Note: SUBSTR removes the carriage-control characters.
This example produces the following output:
ppppp(((((((((
Net: ($45,034)
7070707070282828282828282828
The line of text consists of five white characters with no attributes, represented by the
attribute value '70'x, followed by nine red reverse characters, represented by '28'x.
Example 2: Performing a Recursive List Copy
The following statements perform an operation similar to a recursive list copy:
392
Chapter 13
•
SAS Component Language Dictionary
rc=savelist('CATALOG','WORK.TEMP.MYLIST.SLIST',
mylist);
new_list=makelist();
rc=fillist('CATALOG','WORK.TEMP.MYLIST.SLIST',
new_list);
rc=delete('WORK.TEMP.TEMP.SLIST','CATALOG');
Lists that are saved in a permanent catalog with SAVELIST can persist across SAS
sessions.
Example 3: Reading and Printing Out Data and Attributes from LIST
Entries
Consider two LIST entries: SASUSER.DATA.A.LIST, which contains some character
data, and SASUSER.DATA.DATES.LIST, which contains formatted numeric data. The
following program reads the data and attributes from these entries and uses PUTLIST to
print the results.
INIT:
items=makelist();
attrs=makelist();
rc=fillist('catalog','sasuser.data.a.list',
items,attrs);
call putlist(items,'A.LIST contents:',0);
call putlist(attrs,'A.LIST attributes:',0);
rc=fillist('catalog','sasuser.data.dates.list',
items,attrs);
call putlist(items,'DATES.LIST contents:',0);
call putlist(attrs,'DATES.LIST attributes:',0);
rc=dellist(items);
rc=dellist(attrs);
return;
The output for these entries may look like this:
A.LIST contents:('THIS
'
'IS
'
'A
'
'LIST
'
'ENTRY
'
'WITH
'
'EIGHT
'
'ITEMS
'
)[5]
A.LIST attributes:(INFORMAT=''
FORMAT=''
MESSAGE=''
CAPS='Y'
SORTED='N'
NOHONORCASE='Y'
TYPE='C'
JUST='L'
)[7]
DATES.LIST contents:(1765
11162
11813
12072
)[5]
FINFO 393
DATES.LIST attributes:(INFORMAT='DATE.'
FORMAT='DATE.'
MESSAGE=''
CAPS='Y'
SORTED='Y'
NOHONORCASE='N'
TYPE='N'
JUST='L'
)[7]
Note: [5] and [7] are the list identifiers that were assigned when this example was run
and may be different each time the example is run.
See Also
“SAVELIST” on page 633
FINFO
Returns a file information item
Category:
External File
Syntax
item-value=FINFO(file-id,info-item);
Required Arguments
item-value
contains the value of the file parameter, or a blank if info-item is invalid.
Type: Character
file-id
is the identifier that was assigned when the file was opened. If file-id is invalid, the
program halts.
Type: Numeric
info-item
specifies which file information item to retrieve.
Type: Character
Details
FINFO returns the value of a system-dependent information item for an external file.
The information that is available for files depends on the operating system.
FOPTNUM determines how many system-dependent information items are available.
FOPTNAME determines the names of the available items.
Example: Determine if File has LRECL Information
Assign the fileref MYFILE to an external file. Then open the file and determine whether
LRECL (logical record length, an attribute used on some host systems) is one of the
394
Chapter 13
•
SAS Component Language Dictionary
available information items. If the value of the variable CHARVAL is nonblank, then a
value for LRECL is displayed to the user.
rc=filename('myfile',fname);
fid=fopen('myfile');
charval=finfo(fid,'lrecl');
if (charval=' ') then
_msg_= 'The LRECL attribute is not available.';
else
_msg_= 'The LRECL for the file is ' || charval || '.';
rc=fclose(fid);
rc=filename('myfile','');
See Also
•
“DINFO” on page 322
•
“FOPEN” on page 401
•
“FOPTNAME” on page 403
•
“FOPTNUM” on page 404
FKEYNAME
Returns the name of the specified function key
Category:
Keys
Syntax
key-name=FKEYNAME(key-number);
Required Arguments
key-name
contains a function key name as listed in the KEYS window. Function key names
vary according to the device.
Type: Character
key-number
is the number that corresponds to the order in which the keys are displayed in the
KEYS window.
Type: Numeric
Details
The key-number argument identifies a key by its ordinal position in the KEYS window,
not by its label. For example, if the first key in the KEYS window is named PF1, use a 1
rather than PF1 for the key-number argument to identify that key. To retrieve the
corresponding key definitions, use GETFKEY.
You can use this function only in entries that have a DISPLAY window.
FLDATTR 395
Example: Return Key Name
Return the name of function key 12:
keyname=fkeyname(12);
See Also
•
“GETFKEY” on page 423
•
“NUMFKEYS” on page 571
•
“SETFKEY” on page 654
FLDATTR
Changes the color and display attributes of a field, text entry widget, or text label widget to those stored in
an attribute string
Category:
Widget or Field
Syntax
rc=FLDATTR(wcol-name,string);
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
wcol-name
specifies the field, text entry widget, or text label widget to be changed.
Type: Character
string
specifies the color and display attributes to apply and the starting and ending
character positions within the field.
Type: Character
Details
You can use STRATTR or FILLIST to generate the attribute string. You can also
generate the attribute string by assigning hexadecimal values directly to the string.
Table 13.4
Color Attribute Representation
Color
Value
Color
Value
BLUE
'10'x
WHITE
'70'x
396
Chapter 13
•
SAS Component Language Dictionary
Color
Value
Color
Value
RED
'20'x
ORANGE
'80'x
PINK
'30'x
BLACK
'90'x
GREEN
'40'x
MAGENTA
'A0'x
CYAN
'50'x
GRAY
'B0'x
YELLOW
'60'x
BROWN
'C0'x
Table 13.5
Display Attribute Representation
Attribute
Value
NONE
'00'x
HIGHLIGHT
'01'x
UNDERLINE
'02'x
BLINK
'04'x
REVERSE
'08'x
To preserve a color, use the special hexadecimal value 'F0'x. To preserve a display
attribute, use '0F'x. To preserve both the color and display attribute, add the two special
characters together ('FF'x).
For programs with extended tables you must call this function in the getrow section of
your SCL program.
FRAME entry widgets can also use the _setColorStr method.
Example: Change Field Color
Change the first half of the field, ABC, to red reverse.
str=strattr('red','reverse',1,mlength(abc)/2);
rc=fldattr('abc',str);
Suppose the FRAME text entry widget, OBJ1, is BLUE REVERSE. To change the third
through the seventh character positions of OBJ1 to yellow, you must initialize the first
two characters of the attribute string to 'FF'x, then assign YELLOW in the third through
seventh characters. You can assign YELLOW to the attribute string either by using
STRATTR or by assigning the hexadecimal values directly to the string.
st ='FFFF6060606060'x;
rc=fldattr('obj1',str);
The previous example could have been written as follows:
str='FFFF'x;
str=strattr('yellow','',3,5);
rc=fldattr('obj1',str);
FLDCOLOR 397
You can also use the REPEAT function to initialize a string.
str=repeat('FF'x,2 );
str=strattr('yellow','',3,5);
rc=fldattr('obj1',str);
See Also
•
“FLDCOLOR” on page 397
•
“STRATTR” on page 681
FLDCOLOR
Changes the color and display attributes of a field, text entry widget, or text label widget to those stored in
an attribute string
Category:
Widget or Field
Syntax
rc=FLDCOLOR(wcol-name,color,attribute,start,length);
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
wcol-name
specifies the field, text entry widget, or text label widget to be changed.
Type: Character
color
specifies either a color name, or '' to retain the current color. Colors are BLACK,
BLUE, BROWN, CYAN, GRAY, GREEN, MAGENTA, ORANGE, PINK, RED,
WHITE, and YELLOW. SASCOLOR window elements can also be used for color.
Type: Character
attribute
specifies either a display attribute, or '' to retain the current attribute. Attributes are
NONE, BLINKING, HIGHLIGHT, HIREV, REVERSE, and UNDERLINE. If you
specify a SASCOLOR window element for color, then attribute is ignored because
the SASCOLOR window element contains a display attribute. However, you must
specify a placeholder ('') for attribute when you specify arguments after it.
Type: Character
start
specifies the position in the field at which to begin applying the specified color and
display attributes.
398
Chapter 13
•
SAS Component Language Dictionary
Type: Numeric
length
specifies the number of positions to which the specified color and display attributes
are to be applied.
Type: Numeric
Details
FRAME entry widgets can also use the _setColor method.
To change the color for the entire field or FRAME entry widget, you can use the FIELD
function.
Examples
Example 1: Changing the Color and Attributes of Character
Positions
Change the color of the third through seventh character positions in field ABC to red,
and change the display attribute of those positions to high intensity:
rc=fldcolor('abc','red','highlight',3,5);
Example 2: Changing the Color of a Field
Change the color of a field, but leave the attributes the same:
rc=fldcolor('abc','red','',3,7);
Example 3: Using a SASCOLOR Window Element to Change the
Color of a Field
Change the color of a field, using a SASCOLOR window element:
rc=fldcolor('abc','foreground','',3,7);
See Also
•
“FIELD” on page 373
•
“FLDATTR” on page 395
•
“STRATTR” on page 681
FNOTE
Identifies the last record that was read
Category:
External File
Syntax
note-id=FNOTE(file-id);
FNOTE
399
Required Arguments
note-id
contains the identifier assigned to the last record that was read. The note-id value is
used by the FPOINT function to reposition the file pointer on a particular record.
SCL programs should not modify the value of the note-id variable.
Type: Numeric
file-id
is the identifier that was assigned when the file was opened. If file-id is invalid, the
program halts.
Type: Numeric
Details
You can use FNOTE like a bookmark, marking the position in the file so that your
application can later use FPOINT to return to that position.
FNOTE is limited to noting 1,000 records. When that limit is reached, the program halts.
To free the memory that is associated with each note identifier, use DROPNOTE.
Example: Update a File
Assign the fileref THEFILE to an external file. Then attempt to open the file. If the file
is successfully opened, indicated by a positive value in the variable FID, then read the
records, use the variable NOTE3 to save the position of the third record that is read, and
then later use FPOINT to point to NOTE3 to update the file. After the record is updated,
close the file.
/* Assign the fileref THEFILE to the
*/
/* filename stored in the variable FNAME
*/
/* and open it in UPDATE mode.
*/
rc=filename('thefile',fname);
fileid=fopen('thefile','u');
if (fileid>0) then do;
/* Read the first record. */
rc=fread(fileid);
/* Read the second record. */
rc=fread(fileid);
/* Read the third record. */
rc=fread(fileid);
/* Note the position of third record. */
note3=fnote(fileid);
/* Read the fourth record. */
rc=fread(fileid);
/* Read the fifth record. */
rc=fread(fileid);
/* Point to the third record. */
rc=fpoint(fileid,note3);
/* Read the third record. */
rc=fread(fileid);
/* Copy the new text to the FDB. */
rc=fput(fileid,'New text');
/* Update the third record with data in the FDB. */
rc=fwrite(fileid);
/* Close the file. */
400
Chapter 13
•
SAS Component Language Dictionary
rc=fclose(fileid);
end;
/* Deassign the fileref.
rc=filename('thefile','');
*/
See Also
•
“DROPNOTE” on page 337
•
“FPOINT” on page 406
•
“FREAD” on page 411
•
“FREWIND” on page 412
FONTSEL
Opens the selector window for host fonts or for portable fonts
Category:
Selection List
Syntax
newfontlist-id=FONTSEL(oldfontlist-id,font-selector);
Required Arguments
newfontlist-id
contains the identifier of the list that contains the selected font family, size, weight,
and style.
Type: Numeric
oldfontlist-id
contains the identifier of the list that contains the font information for the selection
list. An invalid oldfontlist-id produces an error condition. This list can be empty.
Type: Numeric
font-selector
specifies which font selector window to open:
'Y'
the host font selector window
'N'
the portable font selector window
'H'
the portable font selector window, displaying only the hardware fonts
' ' (blank)
the default font selector window
Type: Character
Details
If oldfontlist-id is not empty, then the selector window opens with the font family, size,
weight, and style selections that are specified in the list. If oldfontlist-id is an empty list,
FOPEN
401
then the selector window opens with the default selections for font family, size, weight,
and style. The newfontlist-id identifier contains information about the font family, size,
weight, and style that the user selected.
The host font selector window enables a user to select fonts that are available on the host
in an environment-specific way. The portable font selector window enables a user to
select a portable font specification, which is used to find the closest match among fonts
that are available on a host. The host font selector window can also be opened from the
portable font selector window by using the System button.
For more information about how to use the font information that is returned, see the
documentation for the extended text entry class in SAS/AF software and its _setFont
method.
To change the default font selector window, use the SAS system option
MULTENVAPPL, which is described in SAS System Options: Reference.
Example: SCL to Open Font Selector Window
Make a FRAME entry with a pushbutton control named PUSHBTN and an SCOM text
entry control named TEXTENTRY1. Clicking on the pushbutton executes the code to
display the portable font selector window. Change the font selector value from N to Y to
use the host font selector window.
INIT:
fontid=makelist();
return;
PUSHBTN:
fontid=fontsel(fontid,'n');
rc=putlist(fontid,'FONT',1);
textentry1.font=fontid;
return;
TERM:
rc=dellist(fontid);
return;
See Also
“MAKELIST” on page 527
FOPEN
Opens an external file
Category:
External File
Syntax
file-id=FOPEN(fileref<,open-mode<,record-length<,record-format> > > );
Required Arguments
file-id
contains the identifier for the file, or 0 if the file could not be opened.
Type: Numeric
402
Chapter 13
•
SAS Component Language Dictionary
fileref
is the fileref that is assigned to the external file.
Type: Character
Optional Arguments
open-mode
specifies the type of access to the file:
'A'
APPEND mode, which allows writing new records after the current end of
the file.
'I'
INPUT mode, which allows reading only. (This is the default.)
'O'
OUTPUT mode, which defaults to the OPEN mode specified in the host
option in the FILENAME statement or function. If no host option is
specified, it allows writing new records at the beginning of the file. If the
file exists, its contents are overwritten, destroying any previous contents.
If the file does not exist, it is created.
'S'
Sequential input mode, which is used for pipes and other sequential
devices such as hardware ports.
'U'
UPDATE mode, which allows both reading and writing records.
'W'
Sequential output mode, which is used for pipes and other sequential
devices such as hardware ports.
Type: Character
record-length
is the logical record length of the file. To use the existing record length for the file,
either specify a length of 0 or do not provide a value here.
Type: Numeric
record-format
is the record format of the file. To use the existing record format, do not specify a
value here.
'B'
The data is to be interpreted as binary data.
'D'
Use the default record format.
'E'
Use an editable record format.
'F'
The file contains fixed-length records.
'P'
The file contains printer carriage-control characters in a host-dependent
record format.
'V'
The file contains variable-length records.
Type: Character
Details
CAUTION:
Use OUTPUT mode with care. Opening an existing file in OUTPUT mode
overwrites the current contents of the file without warning.
FOPTNAME
403
The FOPEN function opens an external file for reading or updating and returns a file
identifier value that can then be used to identify the open file to other functions. You
must associate a fileref with the external file before calling the FOPEN function.
In SCL you can assign filerefs by using either the FILENAME statement or the
FILENAME function. Under some operating systems, you can also use operating system
commands to assign filerefs.
Operating Environment Information
For z/OS data sets that have the VBA record format, specify 'P' for the record-format
argument.
Example: Open File in Input Mode
•
Assign the fileref MYFILE to an external file. Then attempt to open the file for
input, using all defaults:
rc=filename('myfile',fname);
fid=fopen('myfile');
•
Attempt to open a file for input, not using defaults:
fid=fopen('file2','o',132,'e');
See Also
•
“DOPEN” on page 333
•
“FCLOSE” on page 365
•
“FILENAME” on page 383
•
“FILEREF” on page 386
•
“MOPEN” on page 548
FOPTNAME
Returns the name of an item of information for a file
Category:
External File
Syntax
item-name=FOPTNAME(file-id,item-num);
Required Arguments
item-name
contains the name of the information item, or a blank if an error occurred.
Type: Character
file-id
contains the identifier that was assigned when the file was opened. If file-id is
invalid, the program halts.
Type: Numeric
404
Chapter 13
•
SAS Component Language Dictionary
item-num
is the number of the information item.
Type: Numeric
Details
The number, value, and type of available information items depend on the operating
system.
Example: Write File Information to Log
Retrieve the system-dependent file information items and write them to the log:
length name $ 8;
rc=filename('myfile',fname);
fid=fopen('myfile');
infonum=foptnum(fid);
do j=1 to infonum;
name=foptname(fid,j);
value=finfo(fid,name);
put 'File attribute' name 'has a value of' value;
end;
rc=fclose(fid);
rc=filename('myfile','');
The example produces the following output:
File attribute LRECL has a value of 256.
See Also
•
“DINFO” on page 322
•
“DOPTNAME” on page 334
•
“DOPTNUM” on page 335
•
“FINFO” on page 393
•
“FOPEN” on page 401
•
“FOPTNUM” on page 404
•
“MOPEN” on page 548
FOPTNUM
Returns the number of information items that are available for an external file
Category:
External File
Syntax
num-items=FOPTNUM(file-id);
FORMAT 405
Required Arguments
num-items
contains the number of information items that are available.
Type: Numeric
file-id
contains the identifier that was assigned when the file was opened. If file-id is
invalid, the program halts.
Type: Numeric
Details
The number, value, and type of available information items depend on the operating
system.
Use FOPTNAME to determine the names of the items that are available for a particular
operating system. Use FINFO to retrieve the value of a particular information item.
Example: Determine File Attribute Count
Open the external file that has the fileref MYFILE and determine how many systemdependent file information items are available:
fileid=fopen('myfile');
infonum=foptnum(myfile);
See Also
•
“DINFO” on page 322
•
“DOPTNAME” on page 334
•
“DOPTNUM” on page 335
•
“FINFO” on page 393
•
“FOPTNAME” on page 403
FORMAT
Verifies that the specified format is valid
Category:
Formatting
Syntax
rc=FORMAT(format,type);
Required Arguments
rc
contains the return code for the operation:
1
successful
0
not successful
406
Chapter 13
•
SAS Component Language Dictionary
Type: Numeric
format
contains a format that is either supplied by SAS or created using the FORMAT
procedure. The format name must contain a period (for example, dollar6. or
dollar8.2).
Type: Character
type
specifies the type of the format:
'C'
character
'N'
numeric.
Type: Character
Details
If the specified format is not known to the SAS session, then the operation is
unsuccessful. The function verifies that valid widths are specified for formats.
See SAS Statements: Reference for details about formats.
Examples
Example 1: Verifying the Validity of a Character Format
Assume that you want to use the $CHAR12. format and to verify that $CHAR12. is a
valid character format. (If the format name is valid, then the value returned to the
variable RC is 1.)
rc=format('$char12.','c');
Example 2: Verifying the Validity of a Numeric Format
Verify that 5.6 is not a valid format for numeric values. (If it is not valid, then the value
returned to the variable RC is 0.)
rc=format('5.6','n');
See Also
“INFORMAT” on page 467
FPOINT
Positions the “read” pointer on the next record to be read
Category:
External File
Syntax
sysrc=FPOINT(file-id,note-id);
FPOINT 407
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
file-id
contains the identifier that was assigned when the file was opened. If file-id is
invalid, the program halts.
Type: Numeric
note-id
contains the identifier that was assigned by the FNOTE function.
Type: Numeric
Details
Use FNOTE to provide the note-id value that identifies the record. FPOINT determines
only the record to read next. It has no impact on which record is written next. When you
open the file for update, FWRITE writes to the most recently read record.
Example: Update a File
Assign the fileref MYFILE to an external file. Then attempt to open the file. If the file is
opened successfully, then read the records and use NOTE3 to store the position of the
third record read. Later, point back to NOTE3 to update the file, closing the file
afterward.
/* Assign the fileref MYFILE to the physical
/* filename stored in the variable FNAME
/* and open it in UPDATE mode.
rc=filename('myfile',fname);
fileid=fopen('myfile','u');
if (fileid>0) then do;
/* Read the first record. */
rc=fread(fileid);
/* Read the second record. */
rc=fread(fileid);
/* Read the third record. */
rc=fread(fileid);
/* Note the position of the third record.
note3=fnote(fileid);
/* Read the fourth record. */
rc=fread(fileid);
/* Read the fifth record. */
rc=fread(fileid);
/* Point to the third record. */
rc=fpoint(fileid,note3);
/* Read the third record. */
rc=fread(fileid);
/* Copy the new text to the FDB. */
rc=fput(fileid,'new text');
*/
*/
*/
*/
408
Chapter 13
•
SAS Component Language Dictionary
/* Write data in the FDB to the third record. */
rc=fwrite(fileid);
/* Close the file. */
rc=fclose(fileid);
end;
/* Clear the fileref. */
rc=filename('myfile','');
See Also
•
“DROPNOTE” on page 337
•
“FNOTE” on page 398
•
“FREAD” on page 411
•
“FREWIND” on page 412
FPOS
Sets the position of the column pointer in the File Data Buffer
Category:
External File
Syntax
sysrc=FPOS(file-id,nval);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
file-id
contains the identifier that was assigned when the file was opened. If file-id is
invalid, the program halts.
Type: Numeric
nval
is the number of the column at which to set the pointer.
Type: Numeric
Details
If the specified position is past the end of the current record, then the size of the record is
increased appropriately. However, in a fixed block file or a VBA file, if you specify a
column position beyond the end of the record, the record size does not change, and the
text string is not written to the file.
FPUT 409
Example: Position Column Pointer
Assign the fileref THEFILE to an external file and then attempt to open the file. If the
file is opened successfully, as indicated by a positive value in the variable FID, then
place data into the file's buffer at column 12, write the record, and close the file.
/* Assign the fileref THEFILE to the physical */
/* filename stored in the variable FNAME
*/
/* and open it in append mode.
*/
rc=filename('thefile',fname);
fileid=fopen('thefile','o');
if (fileid>0) then do;
rc=fread(fileid);
dataline='This is some data.';
/* Position at column 12 in the FDB. */
rc=fpos(fileid,12);
/* Put the data in the FDB. */
rc=fput(fileid,dataline);
/* Write the record. */
rc=fwrite(fileid);
/* Close the file. */
rc=fclose(fileid);
end;
/* Clear the fileref. */
rc=filename('thefile','');
See Also
•
“FCOL” on page 366
•
“FPUT” on page 409
FPUT
Moves data to the File Data Buffer (FDB) for an external file, starting at the FDB's current column position
Category:
External File
Syntax
sysrc=FPUT(file-id,cval<, length> );
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
file-id
contains the identifier that was assigned when the file was opened. If file-id is
invalid, the program halts.
410
Chapter 13
•
SAS Component Language Dictionary
Type: Numeric
cval
is the data to be moved to the FDB.
Type: Character
Optional Argument
length
is the length of the string to move to the FDB. If length is greater than cval, then the
string is padded with blanks when it is moved. If length is less than cval, the string is
truncated when it is moved. If length is less than 1, the program halts.
Type: Numeric
Details
The unformatted value of cval is passed to FPUT. The number of bytes moved to the
FDB is determined by the length of the variable, or by the value of length, if length is
specified. The value of the column pointer is then incremented to one position past the
end of the new text.
Example
Move data to the FDB and write it to the external file:
/* Assign the fileref THEFILE to the physical */
/* filename stored in the variable FNAME
*/
/* and open it in append mode.
*/
rc=filename('thefile',fname);
fileid=fopen('thefile','a');
if (fileid>0) then
do;
thestring='This is some data.';
rc=fput(fileid,thestring);
rc=fwrite(fileid);
rc=fclose(fileid);
end;
else
_msg_=sysmsg();
rc=filename('thefile','');
See Also
•
“FNOTE” on page 398
•
“FPOINT” on page 406
•
“FPOS” on page 408
•
“FWRITE” on page 421
_FRAME_
Contains the identifier of either the FRAME entry that contains the control or the FRAME entry that is being
used as a method
FREAD
Category:
411
System Variable
Details
_FRAME_ is a system variable that is provided automatically by the FRAME entry in
SAS/AF software. A space is automatically created for it in the SCL data vector (SDV).
_FRAME_ contains the identifier of the FRAME entry that contains a component.
Otherwise, it contains the identifier of the FRAME that is running.
You can use this variable to send methods to a FRAME entry from a control's method.
For example, a control method can send a _refresh method to the FRAME entry, causing
the FRAME entry to refresh its display.
Example: Run FRAME Entry on Select
Suppose the entry FIRST.FRAME contains an icon. The icon's _select method is defined
to run the SAS/AF FRAME entry SECOND.FRAME, which contains the following
program:
INIT:
/* Send a method to the current FRAME */
_CFRAME_._setMsg('Running the Select method');
return;
TERM:
/* Send a method to the FRAME that */
/* contains the icon
*/
_FRAME_._setMsg('Select method has finished.');
return;
When FIRST.FRAME displays and a user selects the icon, SECOND.FRAME displays
with the message “Running the Select method”. After the user ends from
SECOND.FRAME, FIRST.FRAME displays the message “Select method has finished.”
This is accomplished by sending the _setMsg method to _CFRAME_ (the FRAME entry
that is currently running) in the INIT section and by sending _setMsg to _FRAME_ (the
FRAME entry that contains the icon) in the TERM section.
See Also
“_CFRAME_” on page 248
FREAD
Reads a record from an external file into the File Data Buffer (FDB)
Category:
External File
Syntax
sysrc=FREAD(file-id);
Required Arguments
sysrc
contains the return code for the operation:
412
Chapter 13
•
SAS Component Language Dictionary
0
successful
≠0
not successful
Type: Numeric
file-id
contains the identifier that was assigned when the file was opened. If file-id is
invalid, the program halts.
Type: Numeric
Details
The position of the file pointer is automatically updated after the read operation so that
successive FREAD functions read successive file records.
Use FNOTE, FPOINT, and FREWIND to position the file pointer explicitly.
Example
Assign the fileref MYFILE to an external file and attempt to open the file. Read each
record from the file and list it in the LOG window.
/* Assign the fileref MYFILE to the physical */
/* filename stored in the variable FNAME
*/
/* and open it.
*/
rc=filename('myfile',fname);
fileid=fopen('myfile');
if (fileid>0) then
do while(fread(fileid)=0);
rc=fget(fileid,c,200);
put c;
end;
rc=fclose(fileid);
rc=filename('myfile','');
See Also
•
“FGET” on page 372
•
“FNOTE” on page 398
•
“FPOINT” on page 406
•
“FREWIND” on page 412
FREWIND
Positions the file pointer at the beginning of the file
Category:
External File
Syntax
sysrc=FREWIND(file-id);
FRLEN
413
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
file-id
contains the identifier that was assigned when the file was opened. If file-id is
invalid, the program halts.
Type: Numeric
Details
FREWIND has no effect on a file that was opened with sequential access.
Example
Assign the fileref THEFILE to an external file. Then open the file and read the records
until the end of the file is reached. The FREWIND function then repositions the pointer
to the beginning of the file. The first record is read again and is stored in the File Data
Buffer (FDB). The first token is retrieved and is stored in the variable VAL.
/* Assign the fileref THEFILE to the physical
/* filename stored in the variable FNAME
/* and open it.
rc=filename('thefile',fname);
fileid=fopen('thefile');
do while (rc ne −1);
/* Read a record. */
rc=fread(fileid);
end;
/* Reposition the pointer at the beginning of
/* the file.
if rc= -1 then rc=frewind(fileid);
/* Read the first record. */
rc=fread(fileid);
/* Read the first token into VAL. */
rc=fget(fileid,val);
put val= ;
rc=fclose(fileid);
rc=filename('thefile','');
*/
*/
*/
*/
*/
See Also
“FGET” on page 372
FRLEN
Returns the size of the last record read, or, if the file is opened for output, returns the current record size
Category:
External File
414
Chapter 13
•
SAS Component Language Dictionary
Syntax
length=FRLEN(file-id);
Required Arguments
length
contains the length of the current record if the file is opened for output. Otherwise, it
is the length of the last record read.
Type: Numeric
file-id
is the identifier that was assigned when the file was opened. If file-id is invalid, the
program halts.
Type: Numeric
Example
Open the file identified by the fileref THEFILE. Determine the minimum and maximum
lengths of records in the external file, and write the results to the LOG window.
/* Assign the fileref THEFILE to the physical */
/* filename stored in the variable FNAME
*/
/* and open it.
*/
rc=filename('thefile',fname);
fileid=fopen('thefile');
min=0;
max=0;
if (fread(fileid)=0) then do;
min=frlen(fileid);
max=min;
do while(fread(fileid)=0);
reclen=frlen(fileid);
if (reclen>max) then max=reclen;
if (reclen<min) then min=reclen;
end;
rc=fclose(fileid);
end;
put min= max=;
See Also
•
“FCLOSE” on page 365
•
“FOPEN” on page 401
•
“FREAD” on page 411
FSEDIT
Displays a SAS table by row
Category:
SAS Table
FSEDIT
415
Syntax
CALL FSEDIT(table-name<,screen-name<,open-mode<,row-number> > > );
Required Argument
table-name
is the SAS table to display, in the form <libref.>member-name<(data-set-options)>.
If you omit the libref, the default WORK library is used.
You can add a list of SAS data set options in parentheses following the table name.
All data set options are valid except FIRSTOBS= and OBS=. See SAS Data Set
Options: Reference for a list of SAS data set options and their descriptions.
Type: Character
Optional Arguments
screen-name
is a SCREEN entry for the FSEDIT session. (Screen entries are SAS catalog entries
of type SCREEN that define custom features for the FSEDIT session.) For screenname, use the form <libref.>catalog-name<.entry-name<.SCREEN>>. A one- or
two-level name is interpreted as a catalog name, and the default screen entry name,
FSEDIT.SCREEN, is assumed. (A one-level name is interpreted as a catalog in the
default SAS data library, WORK.) If the specified catalog does not already exist, it is
created.
If the screen entry does not already exist, a new screen entry is not created unless the
user issues a MODIFY command during the FSEDIT session.
If you want to use predefined SAS table labels, use an equal sign (=) for screenname. (A modified SCREEN entry is not saved.) Column names are used for any
fields that lack labels.
Type: Character
open-mode
specifies the type of access to the SAS table:
'ADD'
adds a new blank row to the table, then opens the FSEDIT window with the new
row displayed for editing.
'BROWSE'
opens the FSBROWSE window for reading rows.
'EDIT'
opens the FSEDIT window for editing rows. (This is the default.)
'NEW'
opens the FSEDIT NEW window for creating the specified SAS table as a new
table, then opens the FSEDIT window for entering values into the new table.
Type: Character
row-number
is the first row to be displayed when the FSEDIT or FSBROWSE window is opened.
This argument is ignored unless the value of open-mode is 'EDIT' or 'BROWSE'.
Type: Numeric
416
Chapter 13
•
SAS Component Language Dictionary
Details
The FSEDIT routine calls the FSEDIT procedure, which opens the FSEDIT window to
display the specified SAS table. You can specify BROWSE for open-mode to open the
FSBROWSE window for browsing the table instead. You can optionally specify the
name of a screen entry to provide a custom display and the number of the row to be
displayed when the window is opened.
If you want to specify open-mode or row-number but do not want to specify a screen
entry, use a null string ('') for screen-name.
To use the FSEDIT routine, SAS/FSP Software must be installed. For more information
about the commands that are available in the FSEDIT procedure, see the SAS/FSP
Procedures Guide.
Example:
•
Open a SAS table named PERSONAL (in the default SAS data library WORK) for
editing:
call fsedit('personal');
•
Open the SAS table PERSONAL in the library MASTER for editing, using a custom
SCREEN entry named PER1 in the catalog MASTER.DISPLAY:
call fsedit ('master.personal','master.display.per1');
•
Open a SAS table named MASTER.PERSONAL for browsing, using the default
FSBROWSE window display:
call fsedit('master.personal',' ','browse');
•
To display the predefined labels that are associated with the SAS table columns
instead of the column names, specify an equal sign (=) for the screen-name
argument, as in the following example:
call fsedit('master.personal','=','browse');
Specify SAS data set options by enclosing them within parentheses immediately
following the SAS table name in the table-name argument, as in the following examples.
•
Open a SAS table named MASTER.PERSONAL and subset the rows based on the
value that is entered for the numeric column SCRNUM:
call fsedit('master.personal(where=(num='||
put(scrnum,5.)||'))');
•
Open a SAS table named MASTER.PERSONAL and subset the rows based on the
value that is entered for the character column SCRNAME:
call fsedit('master.personal(where=(name='||
quote(scrname)||'))');
See Also
“NEW” on page 558
FSEP
Sets the token delimiters for the FGET function
Category:
External File
FSEP
417
Syntax
sysrc=FSEP(file-id,delimiter);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
file-id
specifies the identifier that was assigned when the file was opened. If file-id is
invalid, the program halts.
Type: Numeric
delimiter
specifies the token delimiter that separates items in the File Data Buffer (FDB). If
multiple characters are specified, each character is considered a delimiter. The
default delimiter is a blank.
Type: Character
Example
Suppose the external file contains data in this form:
John J. Doe,Male,25,Weight Lifter
Note that each field is separated by a comma.
Read the file identified by the fileref THEFILE, using the comma as a separator, and
write the values for NAME, GENDER, AGE, and WORK to the LOG window:
fileid=fopen('thefile');
rc=fsep(fileid,',');
sysrc=fread(fileid);
rc=fget(fileid,cval);
do while (rc ne -1);
put cval=;
rc=fget (fileid,cval);
end;
rc=fclose(fileid);
The output of the program is
cval=John J. Doe
cval=Male
cval=25
cval=Weight Lifter
See Also
•
“FGET” on page 372
418
Chapter 13
•
SAS Component Language Dictionary
•
“FREAD” on page 411
FSLIST
Displays an external file for browsing
Category:
External File
Syntax
CALL FSLIST(file<,options> );
Required Argument
file
is the fileref or physical filename of the external file. A physical name must be
enclosed in quotation marks.
Type: Character
Optional Argument
options
specifies one or more carriage-control options for formatting the display, with
multiple options separated by blanks and enclosed in one set of quotation marks:
'CC'
Use the host operating system's native carriage-control characters.
'FORTCC'
Use FORTRAN-style carriage-control characters.
'NOCC'
Treat carriage-control characters as regular text. (This is the default.)
For CC or FORTCC, you can also specify an overprinting control option:
'OVP'
Print the current line over the previous line when the overprint code is
encountered. The OVP option is valid only if the CC or FORTCC option is also
specified. The default is NOOVP.
'NOOVP'
Ignore the overprint code and print each line from the file on a separate line of
the display.
If you use the FORTCC option, the first column of each line in the external file is not
displayed. The character in this column is interpreted as a carriage-control code.
Under some operating systems, FORTRAN-style carriage control is the native
carriage control. For these systems, the FORTCC and CC options produce the same
behavior.
Under some operating systems, the CC option is the default for print files.
Type: Character
FSVIEW
419
Details
The FSLIST routine calls the FSLIST procedure, which opens the FSLIST window to
display an external file for interactive browsing. This routine provides a convenient
method for examining the information stored in an external file.
For more information, see Chapter 27, “FSLIST Procedure” in Base SAS Procedures
Guide.
External files (files maintained by the host operating system rather than by SAS
software) can contain various types of information:
•
data records
•
output from previous SAS sessions
•
SAS source statements
•
carriage-control information.
Example:
•
Browse an external file to which the fileref MYFILE has previously been assigned.
The file contains FORTRAN-style carriage-control characters, and overprinting is
allowed.
call fslist('myfile','fortcc ovp');
•
Browse the external file named FSLIST.PUB. Double quotation marks surrounding
the filename string indicate that a physical filename, not a fileref, is being passed to
the FSLIST routine.
call fslist('"fslist.pub"');
Note: The form of the physical filename depends on the host operating system.
See Also
“FILENAME” on page 383
FSVIEW
Displays a SAS table in tabular format
Category:
SAS Table
Syntax
CALL FSVIEW(table-name<,open-mode<,formula-entry<,options> > > );
Required Argument
table-name
is the SAS table to be displayed. Use the format <libref.>member-name<(data-set
options)>. If the libref is omitted, the default SAS data library, WORK, is assumed.
You can add a list of SAS data set options in parentheses following the table name.
All data set options are valid except FIRSTOBS= and OBS=. Refer to SAS Data Set
Options: Reference for a list of SAS data set options and their descriptions.
420
Chapter 13
•
SAS Component Language Dictionary
Type: Character
Optional Arguments
open-mode
specifies the type of access to the SAS table:
'ADD'
Add a new blank row to the table, and then open the FSVIEW window with the
new row displayed for editing.
'BROWSE'
Open the FSVIEW window for reading rows. (This is the default.)
'EDIT'
Open the FSVIEW window for editing rows.
'NEW'
Open the FSVIEW NEW window for creating the specified SAS table as a new
table, then open the FSVIEW window for entering values into the new table.
Type: Character
formula-entry
is the FORMULA catalog entry that defines custom features for the FSVIEW session
or that controls the display and behavior of the session.
Specify this argument as <libref.>catalog-name<.entry-name<.FORMULA>>. A
one- or two-level name is interpreted as a catalog name, and the default formula
entry name is assumed. The default formula entry name is the same as the member
name of the table specified in the table-name argument. (A one-level name is
assumed to refer to a catalog in the default SAS data library, WORK.) If the
specified catalog does not exist, it is created. If the specified formula entry does not
already exist, a new formula entry is created.
Type: Character
options
specifies whether to disable certain FSVIEW window commands for the duration of
the FSVIEW session. Separate multiple options with blanks.
'BRONLY'
disables the MODIFY command so that only browsing is allowed and 'EDIT'
and 'ADD' modes are ignored.
'NOADD'
disables the ADD command so that new rows cannot be added to the table.
'NODELETE'
disables the DELETE command so that rows cannot be deleted.
Type: Character
Details
The FSVIEW routine calls the FSVIEW procedure, which opens the FSVIEW window
to display the specified SAS table. By default, the SAS table is opened for browsing.
You can use the open-mode argument to specify that the table should instead be opened
for editing. You can also specify a formula entry and other options for the FSVIEW
session.
FWRITE
421
If you specify NEW for the open-mode argument, the FSVIEW NEW window is opened
for the user to define a new SAS table before the FSVIEW window is opened to enter
values for that table.
You can specify SAS data set options by enclosing them within parentheses immediately
following the SAS table name in the table-name argument, as in the second example in
the "Examples" section.
If you want to specify the options argument but do not want to specify a formula entry,
then use a null string ('') for the formula-name argument.
To specify multiple values for the options argument, separate the values with blanks.
In order to use the FSVIEW routine, SAS/FSP Software must be installed. For more
information about the commands that are available in the FSVIEW procedure, see the
SAS/FSP Procedures Guide.
Example:
•
Browse a SAS table named PERSONAL in the default SAS data library WORK:
call fsview('personal');
•
Edit a SAS table named PERSONAL in the library MASTER. Only those rows in
which the SITE column has the value 5 are displayed.
call fsview
('master.personal(where=(site=5))','edit');
•
Edit a SAS table named PERSONAL in the library MASTER. Rows cannot be
added or deleted during the FSVIEW session.
call fsview
('master.personal','edit','','noadd nodelete');
See Also
•
“FSEDIT” on page 414
•
“NEW” on page 558
FWRITE
Writes a record to an external file
Category:
External File
Syntax
sysrc=FWRITE(file-id<,cc> );
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
422
Chapter 13
•
SAS Component Language Dictionary
Type: Numeric
file-id
contains the identifier that was assigned when the file was opened. If file-id is
invalid, the program halts.
Type: Numeric
Optional Argument
cc
specifies a carriage-control character:
'0'
skips one blank line before a new line.
'-'
skips two blank lines before a new line.
'1'
starts the line on a new page.
'+'
overstrikes the line on a previous line.
'P'
interprets the line as a terminal prompt.
'='
interprets the line as carriage-control information.
Any other character (including a blank) starts the record on a new line.
If cc is not provided, FWRITE writes to the current line.
Type: Character
Details
FWRITE moves text from the File Data Buffer (FDB) to the external file. In order to use
the carriage-control characters, you must open the file with a RECORD format of P
(PRINT format) with FOPEN.
Example
Write the numbers 1 to 50 to an external file, skipping two blank lines. Then call
FSLIST to display the newly created file.
/* Assign the fileref THEFILE to the external */
/* filename stored in the variable FNAME.
*/
rc=filename('thefile',fname);
fileid=fopen('thefile','o',0,'P');
do i=1 to 50;
rc=fput(fileid,put(i,2.));
if (fwrite(fileid,'-') ne 0) then do;
_msg_=sysmsg();
put msg;
return;
end;
end;
rc=fclose(fileid);
call fslist('thefile','cc');
See Also
•
“FAPPEND” on page 363
GETFKEY 423
•
“FGET” on page 372
•
“FPUT” on page 409
GETFKEY
Returns the command that is assigned to a function key
Category:
Keys
Syntax
key-command=GETFKEY(key-name);
Required Arguments
key-command
returns the command that is currently assigned to the function key.
Type: Character
key-name
specifies the name of the function key as listed in the KEYS window. Function key
names vary according to the device. Use FKEYNAME to retrieve the name of a
function key.
Type: Character
Details
GETFKEY returns the command that is assigned to a function key for the current
window. This is the same as the text displayed for the key in the KEYS window.
You can use this function only in entries that have a DISPLAY window.
Examples
Example 1: Using GETFKEY When the Function Key Name Is
Unknown
Return the command assigned to the first function key if the name of the function key is
not known:
command=getfkey(fkeyname(1));
Example 2: Using GETFKEY When the Function Key Name Is Known
If the value of the first function key is F1, return the command that is assigned to the
first function key:
command=getfkey('F1');
See Also
•
“FKEYNAME” on page 394
•
“NUMFKEYS” on page 571
424
Chapter 13
•
SAS Component Language Dictionary
•
“SETFKEY” on page 654
GETFOOT
Returns the text of a footnote definition
Category:
SAS System Option
Syntax
foot-text=GETFOOT(foot-num);
Required Arguments
foot-text
contains the text of the footnote definition, or a blank if the footnote is not defined.
Type: Character
foot-num
is the number (1 to 10) of the footnote definition.
Type: Numeric
Details
Use GETFOOT to retrieve any footnote text that was previously defined in the SAS
session by either the FOOTNOTE statement or the SCL SETFOOT routine. Only the
footnote text is retrieved. Graphic options such as color or font are not returned.
You can view footnotes in the FOOTNOTES window by using the FOOTNOTE
command. Changing any text in the FOOTNOTES window, however, resets all
graphically defined FOOTNOTE options, such as color, font, and position.
For more information about footnotes, see SAS Statements: Reference. For more
information about graphical footnotes, see SAS/GRAPH: Reference.
Example
Store the text of FOOTNOTE2 in the variable FNOTE2:
fnote2=getfoot(2);
See Also
•
“GETTITLE” on page 433
•
“SETFOOT” on page 656
•
“SETTITLE” on page 672
GETITEMC, GETITEML, GETITEMN, and GETITEMO
Returns a value that is identified by its position in an SCL list
Category:
List
GETITEMC, GETITEML, GETITEMN, and GETITEMO 425
Syntax
cval=GETITEMC(list-id<,index> );
sublist-id=GETITEML(list-id<,index> );
nval=GETITEMN(list-id<,index> );
object-id=GETITEMO(list-id<,index> );
Required Arguments
cval
contains the character value (returned by GETITEMC) of the item that is stored at
the specified position in list identified by list-id.
Type: Character
sublist-id
contains the list identifier (returned by GETITEML) of the sublist that is stored at the
specified position in the list identified by list-id.
Type: Numeric
nval
contains the numeric value (returned by GETITEMN) of the item that is stored at the
specified position in the list identified by list-id.
Type: Numeric
object-id
contains the object identifier (returned by GETITEMO) of the object that is stored at
the specified position in the list identified by list-id.
Type: Numeric
list-id
contains the identifier of the list that you want to query. An invalid list-id produces
an error condition.
Type: Numeric or List
Optional Argument
index
is the position in the list of the item to return. The position can be specified as a
positive or negative number. By default, index is 1 (the first item). If index is a
positive number, then the item is at position index from the beginning of the list. If
index is a negative number, then the item is at position ABS(index) from the end of
the list. An error condition results if the absolute value for index is zero or if it is
greater than the number of items in the list.
Type: Numeric
Details
An error results if you use any of these functions to return an indexed item that has a
different data type. You can determine the data type of an item in a list by using
ITEMTYPE before using GETITEMC, GETITEML, GETITEMN, or GETITEMO.
426
Chapter 13
•
SAS Component Language Dictionary
Examples
Example 1: Using the GETITEMC Function
Return the character values stored in the first and third items of the list identified by the
MYLIST variable:
citem=getitemc(mylist);
citem=getitemc(mylist,3);
Example 2: Using the GETITEML Function
Return the list identifier stored in the eighth item of the list identified by the MYLIST
variable:
slist=getiteml(mylist,8);
Example 3: Using the GETITEMN Function
Return the numeric value stored in the fifth item of the list identified by the MYLIST
variable:
nitem=getitemn(mylist,5);
Example 4: Using the GETITEMO Function
Return the object identifiers stored in the third and ninth item of the list identified by the
MYLIST variable:
sublist=getitemo(mylist,3);
oitem=getitemo(mylist,9);
See Also
•
“GETNITEMC, GETNITEML, GETNITEMN, and GETNITEMO” on page 429
•
“POPC, POPL, POPN, and POPO” on page 592
•
“SETITEMC, SETITEML, SETITEMN, and SETITEMO” on page 657
GETLATTR
Returns the attributes of either an SCL list or an item in the list
Category:
List
Syntax
attributes=GETLATTR(list-id<,index> );
Required Arguments
attributes
contains a string of words separated by blanks. Each word is a separate attribute for a
list or item.
Type: Character
GETLATTR 427
list-id
contains the identifier of the list that GETLATTR processes. An invalid list-id
produces an error condition.
Type: Numeric or List
Optional Argument
index
is the position of the item in the list. The position can be specified as a positive or
negative number. By default, index is 1 (the first item). If index is a positive number,
then the item is at position index from the beginning of the list. If index is a negative
number, then the item is at position ABS(index) from the end of the list. An error
condition results if the absolute value for index is zero or if it is greater than the
number of items in the list.
If index is 0 or is omitted, then the attributes returned by GETLATTR are list
attributes. If index is nonzero, then GETLATTR returns the attributes associated with
the indexed item instead of the attributes for the entire list.
Type: Numeric
Details
The items in attributes can be used to assign attributes to another list or item. The string
returned as attributes contains a blank before and after each attribute, which makes it
easy to determine whether an attribute is set by searching attributes for an attribute
name. Use the INDEX function to search the string for a specified attribute.
If index is omitted, attributes contains one attribute from each row of the following
table.
Table 13.6
Attributes Returned When Index is Omitted
Default Setting
Alternate Setting
UPDATE
NOUPDATE
NOFIXEDTYPE
FIXEDTYPE
NOFIXEDLENGTH
FIXEDLENGTH
ANYNAMES
SASNAMES
DUPNAMES
NODUPNAMES
NOCHARONLY
CHARONLY
NONUMONLY
NUMONLY
COPY
NOCOPY
HONORCASE
NOHONORCASE
If index is supplied, then attributes is the set of item attributes consisting of one attribute
from each row of the following table:
428
Chapter 13
•
SAS Component Language Dictionary
Table 13.7
Attributes Returned When Index is Supplied
Default Setting
Alternate Setting
ACTIVE
INACTIVE
DELETE
NODELETE
NOFIXEDTYPE
FIXEDTYPE
UPDATE
NOUPDATE
WRITE
NOWRITE
For detailed information about these attributes, see “SETLATTR” on page 662.
Example: List Attributes
Create a list LISTID with one item and print the sets of list attributes for LISTID as well
as the item attributes that are associated with the first item of LISTID. Note the leading
and trailing blanks in the attribute strings, which are made evident by embedding the
attribute strings in double quotation marks.
INIT:
listid = makelist(1);
listattrs = '"' || getlattr(listid) || '"';
put listattrs=;
found = index(listattrs,'UPDATE');
put found=;
itemattrs = '"' || getlattr(listid,1) || '"';
put itemattrs=;
rc = dellist(listid);
return;
The output of this example is
LISTATTRS=" DELETE UPDATE NOFIXEDTYPE
NOFIXEDLENGTH ANYNAMES DUPNAMES
NOCHARONLY NONUMONLY COPY NOHONORCASE "
FOUND=10;
ITEMATTRS=" ACTIVE WRITE NOAUTO NOEDIT
DELETE UPDATE NOFIXEDTYPE "
FOUND returns the starting position of the word "UPDATE" in the string of list
attributes.
See Also
•
“HASATTR” on page 442
•
“SETLATTR” on page 662
GETNITEMC, GETNITEML, GETNITEMN, and GETNITEMO 429
GETNITEMC, GETNITEML, GETNITEMN, and GETNITEMO
Return a value identified by its item name in an SCL list
Category:
List
Syntax
cval=GETNITEMC(list-id,name<,occurrence <,start-index<,default<,force> > > > );
sublist-id=GETNITEML(list-id,name<,occurrence <,start-index<,default<,force> > > > );
nval=GETNITEMN(list-id,name<,occurrence <,start-index<,default<,force> > > > );
obj-val=GETNITEMO(list-id,name<,occurrence <,start-index<,default<,force> > > > );
Required Arguments
cval
contains the character value that is returned by GETNITEMC.
Type: Character
list-id
is the identifier of the list to search. An invalid list-id produces an error condition.
Type: List
name
is the name of the item to search in the list. Item names are converted to uppercase
during the search if force is 'Y' or if the searched list has the attribute
NOHONORCASE set. Trailing blanks are ignored when the list is searched for a
matching name. Thus, the names 'abc' and 'Abc' are converted to 'ABC'.
IGNORECASE is the alias for NOHONORCASE and is the default for a list. But
you can use the SETLATTR function to set a list's attribute to HONORCASE.
Type: Character
Optional Arguments
occurrence
is the number of the occurrence of the named item to be searched. The default, 1,
indicates the first occurrence of the item.
Type: Numeric or List
start-index
specifies where in the list to begin searching for the item. By default, start-index is 1
(the first item). If start-index is positive, the search begins at position start-index
items from the beginning of the list. If start-index is negative, the search begins at
the item specified by ABS(start-index) items from the end of the list. An error
condition results if the absolute value of start-index is zero or if it is greater than the
number of items in the list.
Type: Numeric
default
is a default value to return if the named item is not found in the list. This value must
have the appropriate data type for the function that is being used:
430
Chapter 13
•
SAS Component Language Dictionary
Type: Character, Numeric, List, or Object
GETNITEMC
a character value
GETNITEML
a sublist identifier or a list value
GETNITEMN
a numeric value
GETNITEMO
an object identifier.
sublist-id
is the identifier for the sublist that is returned by GETNITEML.
Type: List
nval
is the numeric value that is returned by GETNITEMN.
Type: Numeric
obj-val
is the object identifier that is returned by GETNITEMO.
Type: Object
force
specifies whether to conduct the name search in uppercase.
'N'
searches according to the list attributes HONORCASE and
NOHONORCASE, which are specified with SETLATTR. (This is the
default.)
'Y'
conducts the name search in uppercase regardless of list attributes
specified with SETLATTR.
Type: Character
Details
By default, the search starts at the beginning of the list and returns the first item found
that has the specified item name. However, you can start the search at a different place in
the list by specifying a start-index other than 1. You can also specify a different
occurrence of the item (for example, the second, tenth, or twentieth) by specifying an
occurrence other than 1. If the item is not found and you have specified a value for
default as the fifth parameter, then that value is returned instead of an error condition.
If occurrence and start-index are both positive or both negative, the search proceeds
forward from the start-index item. For forward searches, the search continues only to the
end of the list and does not wrap back to the front of the list. If occurrence or start-index
is negative, then the search is backwards. For backward searches, the search continues
only to the beginning of the list and does not wrap back to the end of the list.
GETNITEMC combines the actions of NAMEDITEM and GETITEMC. GETNITEML
combines the actions of NAMEDITEM and GETITEML. GETNITEMN combines the
actions of NAMEDITEM and GETITEMN. GETNITEMO combines the actions of
NAMEDITEM and GETITEMO.
In situations where your application manipulates an SCL list and you cannot guarantee
that the named item is character, you should not use GETNITEMC. Instead, when
GETNITEMC, GETNITEML, GETNITEMN, and GETNITEMO 431
manipulating SCL lists which may contain other types, you should use NAMEDITEM
with ITEMTYPE with GETITEMC, GETITEML, GETITEMN, or GETITEMO.
An error condition results if
•
the named item is not a character value and you are using GETNITEMC
•
the item is not a list identifier and you are using GETNITEML
•
the item is not a numeric value and you are using GETNITEMN
•
the item is not an object and you are using GETNITEMO.
•
the named item does not exist and default is not specified.
Examples
Example 1: Using the GETNITEMC Function
Halt the program if there are fewer than two items named 'Software Sales' in the
list identified by DIRECTORY. Omitting the default value from GETNITEMC
designates that the character item must exist in the list.
s=getnitemc(directory,'Software Sales',2,-1);
This statement is equivalent to the following statements:
ssi=nameditem(directory,'Software Sales',2,-1);
s=getitemc(directory,ssi);
Both of the preceding examples search for the second occurrence of 'Software
Sales', starting from the end of the list.
Example 2: Searching for an Item of Unknown Type
This example shows how to search for a named item in an SCL list when you do not
know the type of that item.
index = nameditem(listid, 'A', occurrence,
startIndex);
if index then
select (itemtype(listid, index));
when ('C') c = getitemc(listid, index);
when ('L') l = getiteml(listid, index);
when ('N') n = getitemn(listid, index);
when ('O') o = getitemo(listid, index);
end;
Example 3: Using GETNITEML and Specifying a Default Value
If the named item may not be in the list, supply a list identifier value for default for
GETNITEML:
sslistid=getniteml
(emp_list,'Marketing',2,-10,-1);
The preceding program statement is equivalent to the following:
mpos=nameditem(emp_list,'Marketing',2,-10);
if mpos ne 0 then
sslistid=getiteml(emp_list,mpos);
else
sslistid=-1;
432
Chapter 13
•
SAS Component Language Dictionary
Example 4: Using GETNITEMC and Specifying a Default Value
This example shows GETNITEMC, using a default value that contains an error message.
defaultc='Value not found';
s=getnitemc
(directory,'Software Sales',2,-1,defaultc);
See Also
•
“GETITEMC, GETITEML, GETITEMN, and GETITEMO” on page 424
•
“NAMEDITEM” on page 551
•
“NAMEITEM” on page 555
•
“SEARCHC, SEARCHL, SEARCHN, and SEARCHO” on page 640
•
“SETLATTR” on page 662
•
“SETNITEMC, SETNITEML, SETNITEMN, and SETNITEMO” on page 667
GETPARMID
Returns the numeric value stored by the SETPARMID routine
Category:
Modular Programming and Object Oriented
Syntax
nval=GETPARMID();
Required Argument
nval
contains the numeric value stored by a previous call to the SETPARMID routine.
Type: Numeric
Details
SETPARMID stores a value, and GETPARMID retrieves the stored value.
SETPARMID and GETPARMID allow only one value to be passed. To pass multiple
values between entries, use the ENTRY statement. Additional ways of making values
available to other SCL programs include using macro variables and SCL lists.
Example
Retrieve the table identifier value that was stored in another program by SETPARMID:
dsid=getparmid();
See Also
•
“DISPLAY” on page 326
•
“ENTRY” on page 346
•
“SETPARMID” on page 670
GETVARC and GETVARN
433
GETTITLE
Returns the text of a title definition
Category:
SAS System Option
Syntax
title-text=GETTITLE(title-num);
Required Arguments
title-text
is the text of the title definition, or a blank if the title is not defined.
Type: Character
title-num
is the number (1 to 10) of the title definition.
Type: Numeric
Details
Use GETTITLE to retrieve any title text that was previously defined in the SAS session
by either the TITLE statement or the SCL SETTITLE routine. Only the title text is
retrieved. Graphic options, such as color or font, are not returned.
You can view titles in the TITLES window by using the TITLE command. Changing
any text in the TITLES window, however, resets all graphically defined title options,
such as color, font, and position.
For more information about titles, see SAS Language Reference: Dictionary. For more
information about graphical titles, see SAS/GRAPH: Reference.
Example
Put the text of TITLE2 into the variable TITLE2:
title2=gettitle(2);
See Also
•
“GETFOOT” on page 424
•
“SETFOOT” on page 656
•
“SETTITLE” on page 672
GETVARC and GETVARN
Assign the value of a SAS table column to an SCL variable
Category:
SAS Table
434
Chapter 13
•
SAS Component Language Dictionary
Syntax
cval=GETVARC(table-id,col-num);
nval=GETVARN(table-id,col-num);
Required Arguments
cval
is the value of the character column that is returned by GETVARC.
Type: Character
table-id
is the identifier for a table that is open. If table-id is invalid, the program halts.
Type: Numeric
col-num
is the number of the column in the Table Data Vector (TDV). This value can be
obtained by using the VARNUM function. If the column specified in col-num is
invalid, the program halts.
Type: Numeric
nval
is the value of the numeric column that is returned by GETVARN.
Type: Numeric
Details
Before you use GETVARC or GETVARN, you can use VARNUM to obtain the number
of a column in a SAS table. You can nest VARNUM, or you can assign it to a column
that can be passed as the second argument. GETVARC and GETVARN read the value
of the specified column that is in the current row in the TDV and copy that value to the
specified SCL variable in the SCL data vector (SDV).
Examples
Example 1: Using GETVARN to Search for a Value
Assign VARNUM to a column that can be passed as the second argument to
GETVARN. Read row number 10 into the TDV.
pricenum=varnum(mydataid,'price');
rc=fetchobs(mydataid,10);
price=getvarn(mydataid,pricenum);
Example 2: Using GETVARC with a Nested VARNUM
Nest VARNUM in the GETVARC function to search for the value of the character
column NAME from the tenth row of the open SAS table whose identifier is stored in
the column MYDATAID.
rc=fetchobs(mydataid,10);
user=getvarc(mydataid,varnum(mydataid,'name'));
See Also
•
“FETCH” on page 368
GETVARF 435
•
“FETCHOBS” on page 369
•
“LOCATEC and LOCATEN” on page 519
•
“PUTVARC and PUTVARN” on page 609
•
“UPDATE” on page 705
•
“VARNUM” on page 721
GETVARF
Assigns the formatted value of a SAS table column to a character SCL variable
Category:
SAS Table
Syntax
cval=GETVARF(table-id,col-num);
Required Arguments
cval
is the formatted value of the table column that is returned by GETVARF.
Type: Character
table-id
is the identifier for a table that is open. If table-id is invalid, the program halts.
Type: Numeric
col-num
is the number of the column in the Table Data Vector (TDV). This value can be
obtained by using the VARNUM function. If the column specified in col-num is
invalid, the program halts.
Type: Numeric
Details
GETVARF assigns the formatted value of a SAS table column to a character SCL
variable. If no format has been assigned to the specified column, GETVARF returns the
raw value for a character column or the value formatted with BEST12. for a numeric
column. The length of the returned value is the width of the format.
Comparisons
This example first creates a SAS table with a character column, NAME, and two
numeric columns, BDAY and GENDER. It then reads each row from the table and prints
the values of each column plus the formatted values of the two numeric columns.
control asis;
submit continue;
proc format; value sexfmt 1='Male' 2='Female';
data work.samplef; input name $ 1-10 bday date. gender;
format bday date. gender sexfmt. ;
cards;
Jane
16oct63 2
436
Chapter 13
•
SAS Component Language Dictionary
Bill
15may62 1
Mary
25jan64 2
;
endsubmit;
id = open ( 'work.samplef');
do while (fetch(id) NE -1);
name = getvarc ( id, 1);
bdayn = getvarn (id, 2);
bday = getvarf (id, 2);
gendern = getvarn (id, 3);
gender = getvarf (id, 3);
put name= bdayn= bday= gendern= gender=;
end;
rc = close (id);
The output would be like the following:
name=Jane bdayn=1384 bday= 16OCT63 gendern=2 gender=Female
name=Bill bdayn=865 bday= 15MAY62 gendern=1 gender=Male
name=Mary bdayn=1485 bday= 25JAN64 gendern=2 gender=Female
See Also
“GETVARC and GETVARN” on page 433
GGLOBAL
Returns the text of a SYMBOL, PATTERN, LEGEND, or AXIS statement
Category:
SAS System Option
Syntax
stmt-text=GGLOBAL(stmt-type,stmt-num);
Required Arguments
stmt-text
contains the text of the retrieved SYMBOL, PATTERN, LEGEND, or AXIS
statement. If stmt-type is invalid, a missing value is returned.
Type: Character
stmt-type
is the type of statement to retrieve:
•
'SYMBOL'
•
'PATTERN'
•
'LEGEND'
•
'AXIS'
Type: Character
GGLOBALE
437
stmt-num
is the number of the SYMBOL, PATTERN, LEGEND, or AXIS statement to
retrieve. Valid values are from 1 to the number of statements that are defined for the
specified type, which is returned by the GGLOBALN function.
Type: Numeric
Details
Because a user can change SYMBOL, PATTERN, LEGEND, or AXIS statements
during the execution of an application, GGLOBALN must be executed before the
GGLOBAL function in order to set up an internal table that is used by GGLOBAL.
Note: SYMBOL and PATTERN can generate more than one definition per statement.
For more information about the SYMBOL, PATTERN, LEGEND, and AXIS
statements, see SAS/GRAPH: Reference.
Example
Assume that the following SYMBOL statements have been defined for the current SAS
session:
symbol1 c=red;
symbol30 c=blue;
Check to see that at least two SYMBOL statements are available. If this condition is
true, the text of the second SYMBOL statement is returned to the variable SYMBOL2.
numsymb=gglobaln('symbol');
if (numsymb >= 2)
then symbol2=gglobal('symbol',2);
The value returned to NUMSYMB is 2. The following value is returned to SYMBOL2:
SYMBOL30 CV=BLUE CO=BLUE CI=BLUE;
The value of HEIGHT is also returned:
SYMBOL30 CV=BLUE CO=BLUE CI=BLUE HEIGHT=1 ;
See Also
•
“GGLOBALE” on page 437
•
“GGLOBALN” on page 438
GGLOBALE
Deletes an internal table of SYMBOL, PATTERN, LEGEND, or AXIS definitions
Category:
SAS System Option
Syntax
sysrc=GGLOBALE(stmt-type);
438
Chapter 13
•
SAS Component Language Dictionary
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
stmt-type
specifies the type of statement to delete:
•
'SYMBOL'
•
'PATTERN'
•
'LEGEND'
•
'AXIS'
Type: Character
Details
When you have completed processing information concerning the SYMBOL,
PATTERN, LEGEND, or AXIS statements, use GGLOBALE to free the memory used
for storing the internal table that was created with GGLOBALN. For more information
about the SYMBOL, PATTERN, LEGEND, and AXIS statements, see SAS/GRAPH:
Reference.
Example
Free the internal table that was created by GGLOBALN for the SYMBOL statements,
and check the return code to determine whether a message needs to be issued:
rc=gglobale('symbol');
if rc then _msg_=sysmsg();
See Also
•
“GGLOBAL” on page 436
•
“GGLOBALN” on page 438
GGLOBALN
Returns the number of SYMBOL, PATTERN, LEGEND, or AXIS statements that are currently defined
Category:
SAS System Option
Syntax
num-stmts=GGLOBALN(stmt-type);
GOTO 439
Required Arguments
num-stmts
contains the number of SYMBOL, PATTERN, LEGEND, or AXIS definitions that
are currently defined.
Type: Numeric
stmt-type
specifies the type of statement to return:
•
'SYMBOL'
•
'PATTERN'
•
'LEGEND'
•
'AXIS'
Type: Character
Details
Information about SYMBOL, PATTERN, LEGEND, or AXIS statements is stored in an
internal table and can be retrieved with GGLOBAL. To delete the internal table created
by GGLOBALN, use GGLOBALE.
Note: SYMBOL and PATTERN can generate more than one definition per statement.
For more information about SYMBOL, PATTERN, LEGEND, and AXIS
statements, see SAS/GRAPH: Reference.
Example
Assume that the following SYMBOL statements have been defined for the current SAS
session:
symbol1 c=red;
symbol30 c=blue;
In the variable NUMSYMB, return the number of SYMBOL statements that are
currently available. The value returned for NUMSYMB is 2, not 30.
numsymb=gglobaln('symbol');
See Also
•
“GGLOBAL” on page 436
•
“GGLOBALE” on page 437
GOTO
Branches immediately to another entry
Category:
Control Flow
Syntax
CALL GOTO(entry<,action<,frame> > );
440
Chapter 13
•
SAS Component Language Dictionary
Required Argument
entry
is the name of the entry to branch to. The entry can be any of the SAS/AF display
entry types (FRAME, PROGRAM, MENU, CBT, or HELP). The entry argument
can be in the following forms:
entry
to specify a PROGRAM entry in the current catalog.
entry.type
to specify an entry in the current catalog.
libref.catalog.entry
to specify a PROGRAM entry in a different catalog.
libref.cat-name.entry.type
to specify an entry in a different catalog.
Type: Character
Optional Arguments
action
specifies how the execution stack is to be handled and where control transfers to
when the specified entry ends:
'A'
adds entry to the top of the execution stack. The specified entry is
displayed immediately. When the entry ends, the user returns to the
window that was displayed before the program with the CALL GOTO was
executed.
'C'
clears the current execution stack. The specified entry is displayed
immediately, and the stack is cleared. When the entry ends, the user
returns to the parent entry, if one was specified in the entry, or exits the AF
window. This option may be useful if you have memory constraints. (This
is the default.)
'R'
removes the top entry from the execution stack and places the entry
specified in the GOTO routine on the top of the execution stack. The
specified entry is displayed immediately. When the entry ends, the user
returns to the next entry on the stack rather than to the program that
contains the GOTO call.
Type: Character
frame
is the number of the CBT frame if you are branching to a CBT entry.
Type: Numeric
Details
The GOTO routine branches immediately to a CBT, HELP, MENU, FRAME, or
PROGRAM entry and transfers control to it. Statements that appear after GOTO are not
executed, because control is transferred to the entry that is specified in the GOTO
routine.
GOTO, which always starts a new stream, cannot be used in FSEDIT or FSVIEW
programs.
GRAY
441
Example
Pass control to MYEND.PROGRAM, and end the SAS/AF session if the user issues the
END command. Assume there is no parent entry specified.
if _status_='E'
then call goto('myend.program','C');
See Also
“DISPLAY” on page 326
GRAY
Grays FRAME entry controls and stations of a choice group
Category:
Control or Field
Syntax
rc=GRAY(var-name <,station <,row> > );
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
var-name
is the name of a window control or choice group to be grayed.
Type: Character
Optional Arguments
station
is the number of the button in a radio box or field in a choice group. This value must
be greater than 0 and no larger than the total number of stations defined for the
choice group. For PROGRAM entries, use the value 0 as a placeholder if the entire
choice group at a specified row is to be grayed.
Type: Numeric
row
is the number of the row when the choice group is in the scrollable section of an
extended table. Row can be used in PROGRAM entry programs but not for FRAME
entry programs. Specify row only when you want to gray a station from outside an
extended table's getrow or putrow section. Do not specify row if you want to gray a
station from a getrow or putrow section.
Type: Numeric
442
Chapter 13
•
SAS Component Language Dictionary
Details
Users cannot select a FRAME entry control, choice group, or choice group station that is
grayed.
For linked action fields in choice groups, the ACTION-type pair is considered one
station. For example, the following line in a PROGRAM entry window defines three
linked action fields:
& &A_____
& &B_____
& &C_____
To gray the linked action pair for field B, pass in 2 for the value of station, not 4.
Window controls can also use the _gray method. You cannot use GRAY in FSEDIT or
FSVIEW programs.
Example
Prevent users from selecting CONTINUE when the value of AGE is less than 21:
if (age<21) then
rc=gray('CONTINUE');
else
rc=ungray('CONTINUE');
See Also
•
“ACTIVATE” on page 215
•
“ISACTIVE” on page 481
•
“ISGRAY” on page 482
•
“UNGRAY” on page 700
HASATTR
Reports whether an SCL list or a list item has a specified attribute
Category:
List
Syntax
rc=HASATTR(list-id, attribute <,index> );
Required Arguments
rc
contains the return code for the operation:
1
The list or item has the specified attribute.
0
The list or item does not have the specified attribute.
Type: Numeric
HASATTR 443
list-id
is the identifier of the list that HASATTR searches. An invalid list-id produces an
error condition.
Type: Numeric or List
attribute
is an attribute for a list or list item, as described in SETLATTR. In addition, you can
test for the following special attributes:
'G'
returns 1 if the list is a global list.
'L'
returns 1 if the list is a local list.
'C'
returns 1 if the list identifier is also a class identifier.
'O'
returns 1 if the list identifier is also an object identifier.
Type: Character
Optional Argument
index
is the position of the item in the list. The position can be specified as a positive or
negative number. By default, index is 1 (the first item). If index is omitted,
HASATTR checks to see if the specified list has the named attribute. If index is
specified, HASATTR checks to see if the specified item has the named attribute. If
index is a positive number, then the item is at position index from the beginning of
the list. If index is a negative number, then the item is at position ABS(index) from
the end of the list. An error condition results if the absolute value for index is zero or
if it is greater than the number of items in the list.
Type: Numeric
Details
If no value is specified for index, HASATTR queries the attribute of the list. If a nonzero
value is specified for index, HASATTR queries the attribute of an item in the list.
For a list of attributes for lists and list items, see “SETLATTR” on page 662.
Examples
Example 1: Clearing a List That Has a Particular Attribute
Clear the list identified by MYLIST only if it has the UPDATE attribute:
if hasattr(mylist,'UPDATE') then rc=clearlist
(mylist);
Example 2: Determining Whether a List Item Has a Particular
Attribute
Determine whether the third item in a list has the FIXEDTYPE attribute:
isfixed=hasattr(mylist,'FIXEDTYPE',3);
See Also
•
“GETLATTR” on page 426
444
Chapter 13
•
SAS Component Language Dictionary
•
“SETLATTR” on page 662
HOME
Positions the cursor on a window's command area
Category:
Control or Field
Syntax
HOME;
Details
In SAS/AF applications, the HOME statement moves the cursor immediately. In
FSEDIT and FSVIEW applications, the cursor is moved when control is returned to the
application.
See “CURSOR” on page 296 for more information about how to position the cursor in a
field.
If the PMENU facility is active, the command area for a dialog window is at the bottom
of the window.
Some systems do not position the cursor on the pull-down menu for standard windows
nor on the command area for dialog windows.
See Also
•
“CURSOR” on page 296
•
“FIELD” on page 373
ICCREATE
Creates integrity constraints on a SAS table
Category:
SAS Table
Syntax
sysrc=ICCREATE(table-id, icname, ictype, icvalue
<, argument-1, argument-2, argument-3>
<, message >
<, msgtype> );
Required Arguments
sysrc
contains the status of the operation:
=0
successful
ICCREATE
>0
not successful
<0
the operation was completed with a warning
445
Type: Numeric
table-id
contains the identifier for the SAS table, which is returned by the OPEN function.
Integrity constraints can be set for a new SAS table only when it is opened in NEW
mode. Integrity constraints can be set for an existing table only when it is opened in
UTILITY or NEW mode. (Remember that if you open an existing table in NEW
mode, the table is replaced without warning.)
Type: Numeric
icname
is the name of the integrity constraint.
Type: Character
ictype
specifies the type of integrity constraint to create:
'CHECK'
specifies that column values must fall within a particular set, range, or list of
values, or that values must meet a condition or be the same as values in other
columns in the same row.
'FOREIGN'
specifies that a column is linked to a column in another SAS table. A foreign key
column can contain only a null value or a value that is present in the associated
primary key column.
'NOT-NULL'
specifies that column values cannot contain missing values.
'PRIMARY'
specifies that column values must be unique and that they cannot be missing
values. If there is an associated foreign key column, then primary key values
cannot be deleted or changed unless the same deletions or changes have been
made in values of that foreign key column.
'UNIQUE' | 'DISTINCT'
specifies that column values must be unique. If more than one column is
specified, then their concatenated values must be unique.
Type: Character
icvalue
specifies the names of one or more columns from the SAS table to which the
constraint is applied. Separate multiple column names with blanks. If ictype is
CHECK, then icvalue can contain a condition that values must meet.
Type: Character
Optional Arguments
argument-1, argument-2, argument-3
are additional specifications that are used when ictype is FOREIGN.
argument-1
is the name of the SAS table in which one or more associated primary keys are
defined. This links the two SAS tables and creates the primary/foreign key
446
Chapter 13
•
SAS Component Language Dictionary
relationship. Use libref.member to specify the SAS table. This argument is
required for foreign keys.
argument-2
is the restriction option for update operations on values in foreign key columns:
'RESTRICT'
allows the primary key value to be updated only if no foreign key matches
the current value to be updated.
'NULL'
specifies that when the primary key value is modified, all matching foreign
key values are set to NULL.
'CASCADE'
specifies that when the primary key value is modified, all matching foreign
key values are set to the same value as the primary key.
argument-3
is the restriction option for delete operations in foreign key columns:
'RESTRICT'
allows the primary key row to be deleted only if no foreign key values match
the deleted value.
'NULL'
allows the primary key row to be deleted and sets the values of corresponding
foreign keys to null.
Type: Character
message
is your own error message that is displayed when a data value fails to comply with
the constraint.
Note
The maximum length for the entire message, including both the user message
and the system message that may be appended to the user message, is 256
characters. If the user message is too long, either the user message or the
system message will be truncated.
message-type
controls how the user-defined error message is displayed.
'NULL'
adds the user-defined message to the beginning of the message that is displayed
by SAS and separates the two message with a blank. This behavior is the default.
'USER'
replaces the SAS message with the user-defined message.
Details
ICCREATE defines integrity constraints for a SAS table that has been opened in an SCL
program. Integrity constraints guarantee the correctness and consistency of data that is
stored in a SAS table. Integrity constraints are enforced automatically for each addition,
update, or deletion of data in a table that contains a constraint.
You can define integrity constraints for SAS tables that contain zero or more rows. For
tables that already contain data, an integrity constraint is compared to values in all table
rows. If a single row does not comply with the constraint being defined, then the creation
of the constraint fails. When rows are added to tables that have integrity constraints, the
new rows are checked against the constraints. If a row violates an integrity constraint,
ICCREATE
447
the row is not added to the table. Also, a primary key column cannot be dropped until all
foreign key columns that reference the primary key are deleted.
The basic types of integrity constraints are general constraints and referential constraints.
The general constraints, which control values in a single SAS table, are CHECK, NOTNULL, PRIMARY key, and UNIQUE. Referential constraints, which establish a parentchild relationship between columns in two SAS tables, include FOREIGN keys and
PRIMARY keys that have one or more FOREIGN key references. A FOREIGN key
column (the child) can contain only null values or values that are present in its associated
PRIMARY key (the parent). Values for a FOREIGN key cannot be added unless the
same values also exist in the associated PRIMARY key.
For more information about integrity constraints, see “Preserving the Integrity of Table
Data in SCL Programs” on page 192.
Example
This example creates integrity constraints for the SAS tables MYLIB.ONE and
MYLIB.TWO. Although they contain different data, they have one column with shared
data, an identifier number that is stored in IDNUM in MYLIB.ONE and in EMPID in
MYLIB.TWO. The following icnames are used in the example:
UQ
is a UNIQUE constraint which specifies that the concatenated values of columns D
and E must be unique.
WH
is a CHECK constraint which specifies that the sum of the values of columns B and
C must be less than 1000.
PK
is a PRIMARY constraint which specifies that the IDNUM column can contain only
unique and non-missing values. Because IDNUM is associated with the foreign key
column EMPID in the table MYLIB.TWO, values for IDNUM cannot be deleted or
changed unless the same changes have been made to the values in the foreign key
EMPID.
FK
is a foreign key in the table MYLIB.TWO. EMPID is the foreign key column whose
primary key is IDNUM in MYLIB.ONE. Because EMPID is a foreign key column, it
can contain only values that are present in IDNUM. The first RESTRICT specifies
that a value in IDNUM can be changed only if EMPID does not contain a value that
matches the IDNUM value to be changed. The second RESTRICT specifies that a
row can be deleted from MYLIB.ONE only if the value of IDNUM does not match a
value in EMPID in MYLIB.TWO.
NONULL
is a NOT-NULL constraint which specifies that the EMPID column cannot contain a
null value.
The first integrity constraints that are defined for each of the tables MYLIB.ONE and
MYLIB.TWO have user-defined messages that will be displayed instead of the SAS
message if any data value does not conform to the integrity constraint.
table1=open('mylib.one','V');
rc=iccreate(table1,'uq','Unique','d e','','','',
'This is my message for uq.','user');
rc=iccreate(table1,'wh','Check','(b + c)< 1000');
rc=iccreate(table1,'pk','Primary','idnum');
rc=close(table1);
448
Chapter 13
•
SAS Component Language Dictionary
table2=open('mylib.two','V');
rc=iccreate(table2,'fk','Foreign','empid','mylib.one',
'restrict','restrict','This is my message for fk.','user');
rc=iccreate(table2,'nonull','Not-null','empid');
...more SCL statements...
rc=close(table1);
rc=close(table2);
See Also
•
“ICDELETE” on page 448
•
“ICDESCRIBE” on page 449
•
“ICTYPE” on page 453
•
“ICVALUE” on page 454
ICDELETE
Drops an integrity constraint from a SAS table
Category:
SAS Table
Syntax
sysrc=ICDELETE(table-id,icname);
Required Arguments
sysrc
contains the status of the operation:
=0
successful
>0
not successful
<0
the operation was completed with a warning
Type: Numeric
table-id
contains the identifier for the SAS table, which is returned by the OPEN function.
An integrity constraint can be dropped only from a SAS table that is open in NEW or
UTILITY mode.
Type: Numeric
icname
is the name of the integrity constraint to delete.
Type: Character
Details
Referential integrity constraints (where ictype is FOREIGN) provide a link between SAS
tables. Part of the link mechanism involves the name of the table. Therefore, renaming or
ICDESCRIBE
449
deleting a table that has a FOREIGN integrity constraint is not allowed until after the
FOREIGN key is deleted.
Comparisons
Delete the integrity constraint UQ from the table MYLIB.ONE. The constraint was
initially created in the example for ICCREATE on page 444.
table1=open('mylib.one','V');
rc=icdelete(table1,'uq');
rc=close(table1);
See Also
•
“ICCREATE” on page 444
•
“ICTYPE” on page 453
•
“ICVALUE” on page 454
ICDESCRIBE
Obtains the attributes for all existing integrity constraints within a specified SAS table
Category:
SAS Table
Syntax
sysrc=ICDESCRIBE(table-id, list-id);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
>0
not successful
<0
the operation was completed with a warning
Type: Numeric
table-id
is the identifier that was assigned when the table was opened. If table-id is invalid,
the function returns a nonzero value.
Type: Numeric
list-id
is the identifier of the list where you want to store the attributes.
Details
This function returns all of the same information that the CONTENTS procedure
displays about the constraints.
For more information about integrity constraints, see “Preserving the Integrity of Table
Data in SCL Programs” on page 192.
450
Chapter 13
•
SAS Component Language Dictionary
Example
The following example creates a SAS table, defines a primary integrity constraint named
PK, and calls ICDESCRIBE to obtain the attributes of PK.
init:
submit continue;
data one;
a=1; b=2; c=3; output; run;
endsubmit;
tableid=open('one','V'); /* utility mode */
rc=iccreate(tableid,'pk','Primary','a');
iclist=makelist();
rc=icdescribe(tableid,iclist);
call putlist(iclist, '', 1);
rc = dellist(iclist, 'Y');
rc=close(tableid);
return;
ICDESCRIBE returns the following information for integrity constraint PK.
( ( NUMVARS=1
NAME='pk'
TYPE='Primary Key'
RECREATE='rc = iccreate( tableid, 'pk', 'primary', 'a', '', '', '', '', '');'
MESSAGE=''
ONDELETE=''
ONUPDATE=''
REF=''
WHERE=''
MSGTYPE=''
VAR1='a'
)[9]
)[5]
See Also
•
“ICCREATE” on page 444
•
“ICDELETE” on page 448
•
“ICTYPE” on page 453
•
“ICVALUE” on page 454
ICON
Associates an icon with a window
Category:
Window
Syntax
rc=ICON(icon-number);
ICREATE
451
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
icon-number
is the number of the icon to use to represent the application window when it is
minimized. If you specify a number for which no icon is defined, the SAS icon is
used.
Type: Numeric
Details
When a user minimizes a window into an icon, SAS uses the specified icon to represent
the window.
Only systems that display icons support this function. Non-graphical devices ignore the
icon setting.
The ICON function is ignored if you are running with the SAS software Application
Work Space (AWS). To run an application without the AWS, specify the AWS=NO
option in the AF command.
Example
Assign icon number 107 as the icon for the current window:
rc=icon(107);
ICREATE
Creates an index for a SAS table
Category:
SAS Table
Syntax
sysrc=ICREATE(table-id,key-name<,var-list<,options>>);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
452
Chapter 13
•
SAS Component Language Dictionary
table-id
is the identifier that was assigned when the table was opened. If table-id is invalid or
if the table is not opened in UTILITY mode, the index is not created and the function
returns a nonzero value.
Type: Numeric
key-name
is the name of the index key to be created.
Type: Character
var-list
is one or more columns from the SAS table to be indexed. Separate multiple names
with blanks.
Type: Character
Optional Argument
options
are index attributes, with multiple values separated by blanks within a single set of
parentheses:
'NONUNIQUE' | 'UNIQUE'
specifies whether the values of the key columns must be unique. The default is
'NONUNIQUE'.
'MISSING' | 'NOMISS'
specifies whether the index can point to missing values. The default is
'MISSING'.
Type: Character
Details
An index is an auxiliary data structure used to speed up searches for records that are
specified by the value of a column (for example, "all the records for which AGE is
greater than 65"). To create an index for a SAS table, you must open the table in
UTILITY mode (see “OPEN” on page 574 for details).
An index on a single column is called a simple index. If var-list contains only one
column name, then a simple index is created.
Note: For a simple index, key-name and var-list must both contain the same value. If
var-list is omitted, then key-name specifies the index column.
An index on more than one column is called a composite index. If var-list contains more
than one column name, a composite index is created. In this case, key-name can be any
valid SAS name that is not already used as a column name in the table. A composite
index is based on the values of these columns, concatenated to form a single value.
UNIQUE specifies that the index contains only unique values of the key columns. The
creation of such an index prohibits duplicate values for its columns from being stored in
the SAS table. For columns that must be uniquely specified in a row, such as passport
numbers, this option is useful for preventing duplicate values from incorrectly getting
into a table. The function returns an error condition if non-unique values are present and
UNIQUE is specified. By default, duplicate values are permitted in an index and thus in
its table.
NOMISS prevents missing values from being pointed to by an index. Unlike UNIQUE,
NOMISS does not prevent missing values from being stored in the SAS table. This
feature is useful if the key columns contain many missing values that would make the
ICTYPE
453
index large and thus slower to access than if they were excluded. By default, missing
values are stored in the index.
Indexes can also be created using
•
the DATASETS and SQL procedures in Base SAS software
•
SAS/IML software
•
the CONTENTS function in SCL
•
the ACCESS procedure in SAS/ACCESS software.
Comparisons
Create a simple index for the SAS table WORK.INVOICE. The key column for the
index is the table column ITEMTYPE.
tableid=open('work.invoice','v');
/* open in UTILITY mode */
rc=icreate(tableid,'itemtype',' ','unique nomiss');
In this example, because the value of the var-list argument is blank, the key column for
the index is the column named in the key-name argument.
See Also
•
“CONTENTS” on page 271
•
“IDELETE” on page 455
•
“IOPTION” on page 480
•
“ISINDEX” on page 483
•
“IVARLIST” on page 488
•
“OPEN” on page 574
ICTYPE
Returns the type of integrity constraint that is assigned to a SAS table
Category:
SAS Table
Syntax
ictype=ICTYPE(table-id,icname);
Required Arguments
ictype
contains the type of integrity constraint that is returned. The constraints are listed
below and are defined in “ICCREATE” on page 444:
•
'CHECK'
•
'FOREIGN'
•
'NOT-NULL'
•
'PRIMARY'
454
Chapter 13
•
SAS Component Language Dictionary
•
'UNIQUE'
Type: Character
table-id
contains the identifier for the SAS table, which is returned by the OPEN function.
Type: Numeric
icname
is the name of the integrity constraint.
Type: Character
Details
ICTYPE returns the type of integrity constraint for a SAS table when you specify the
name of the constraint.
Example
Return the type of the UQ integrity constraint that is assigned to the SAS table
MYLIB.ONE. Because the constraint UQ (which was created in the example for
“ICCREATE” on page 444 ) was UNIQUE, the value of TYPE will be UNIQUE.
tableid=open('mylib.one','i');
type=ictype(tableid,'uq');
...more SCL statements...
rc=close(tableid);
See Also
•
“ICCREATE” on page 444
•
“ICDELETE” on page 448
•
“ICVALUE” on page 454
ICVALUE
Returns the column names or the condition associated with an integrity constraint
Category:
SAS Table
Syntax
icvalue=ICVALUE(table-id,icname);
Required Arguments
icvalue
contains the names of one or more columns from the SAS table identified by tableid. When ictype is CHECK, icvalue returns the condition that values must meet.
Type: Character
table-id
contains the identifier for the SAS table, which is returned by the OPEN function.
IDELETE 455
Type: Numeric
icname
is the name of the integrity constraint.
Type: Character
Details
ICVALUE returns the names of columns that are associated with the specified integrity
constraint. If ictype is CHECK and is specified as a condition, then ICVALUE returns the
condition that is assigned to the constraint.
Example
Return the value of the UQ integrity constraint. If ICVALUE returns a blank, then
display the error message. Because the constraint UQ (which was created in the example
for “ICCREATE” on page 444 ) specified that columns D and E must contain unique
values, COLLIST would contain D E.
tableid=open('mylib.one','i');
collist=icvalue(tableid,'uq');
if (collist=' ') then _msg_=sysmsg();
See Also
•
“ICCREATE” on page 444
•
“ICDELETE” on page 448
•
“ICTYPE” on page 453
IDELETE
Deletes an index from a SAS table
Category:
SAS Table
Syntax
sysrc=IDELETE(table-id,key-name);
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
table-id
is the identifier that was assigned when the table was opened. If table-id is invalid,
the program halts.
456
Chapter 13
•
SAS Component Language Dictionary
Type: Numeric
key-name
is the name of the index key to be deleted.
Type: Character
Details
In order to delete an index for a SAS table, you must open the table in UTILITY mode
(see “OPEN” on page 574 for details).
You can also delete indexes using
•
the DATASETS and SQL procedures in Base SAS software
•
the CONTENTS function in SCL
•
the ACCESS procedure in SAS/ACCESS software.
Example
Delete an index for the SAS table WORK.INVOICE. The name of the index key is
ITEMTYPE.
tableid=open('work.invoice','v');
rc=idelete(tableid,'itemtype');
See Also
•
“CONTENTS” on page 271
•
“ICREATE” on page 451
•
“IOPTION” on page 480
•
“ISINDEX” on page 483
•
“IVARLIST” on page 488
IMGCTRL
Performs control operations on the Image window
Category:
Image
Syntax
rc=IMGCTRL(task-id, command, <other-arguments>);
Required Arguments
rc
contains the return code for the operation:
0
successful
>0
not successful
IMGCTRL 457
Type: Numeric
task-id
contains the identifier of the image task, which is returned by a previous IMGINIT
function.
Type: Numeric
command
is the control command to be executed.
Type: Character
Optional Argument
other-arguments
lists the argument(s) required with each command.
Type: Character
Details
Commands Used with IMGCTRL
For detailed information about these commands, see Appendix 1, “Commands Used with
the IMGCTRL, IMGOP and PICFILL Functions,” on page 795.
'WAIT'seconds
specifies the amount of time to wait before executing the next command. Seconds
specifies the number of seconds to wait.
'WRAISE'
attempts to force the Image window to the top while IMGOP or IMGCTRL
commands are executing. This command may not be honored by some window
managers. Note that the 'TOPWINDOW' option can be set at IMGINIT time to force
the window to always be on top.
'WSIZE'width, height <xpos, ypos>
specifies the width and height of the Image window in pixels. It optionally positions
the window at xpos and ypos of the top left corner. Some window managers may not
support positioning.
'WTITLE'title'
specifies a title for the Image window. The specified title appears in parentheses after
'SAS: IMAGE'.
Examples
Example 1: Using the WTITLE Command
Extract the name of the IMAGE entry and then use the WTITLE command to assign that
name to the window:
path=lnamemk(5,catname,’format=cat’);
rc=lnameget(path,type,name,form);
gname=scan(name,3,’.’);
rc=imgop(taskid,’READ’,path);
rc=imgctrl(taskid,’WTITLE’,gname);
rc=imgop(taskid,’PASTE’,1,1);
458
Chapter 13
•
SAS Component Language Dictionary
Example 2: Using the WAIT Command
Wait 5 seconds before displaying the image after each PASTE command:
rc=imgop(taskid,’READ’,path);
rc=imgop(taskid,’PASTE’);
rc=imgctrl(taskid,’WAIT’,5);
rc=imgop(taskid,’READ’,path2);
rc=imgop(taskid,’PASTE’);
rc=imgctrl(taskid,’WAIT’,5);
Example 3: Using the WRAISE Command
Force the Image window to the top:
pop:
rc=imgctrl(taskid,’WRAISE’);
return;
Example 4: Using the WSIZE Command
Make the Image window match the size of the image that is being displayed:
height=0;
width=0;
rc=imgop(taskid,’READ’,path);
rc=imgop(taskid,’QUERYN’,’WIDTH’,iwidth);
rc=imgop(taskid,’QUERYN’,’HEIGHT’,iheight);
rc=imgctrl(taskid,’WSIZE’,iwidth,iheight);
rc=imgop(taskid,’PASTE’,1,1);
Example 5: Using the WTITLE and WRAISE Commands
Change the window title and then force the Image window to the top:
path=lnamemk(5,catname,’format=cat’);
rc=lnameget(path,type,name,form);
gname=scan(name,3,’.’);
rc=imgop(taskid,’READ’,path);
rc=imgctrl(taskid,’WTITLE’,gname);
rc=imgop(taskid,’PASTE’,1,1);
rc=imgctrl(taskid,’WRAISE’);
IMGINIT
Starts an image task
Syntax
task-id=IMGINIT(<list-id>, <option>);
Required Argument
task-id
contains the identifier for the image task. This identifier is used by other SCL image
functions.
Type
Numeric
IMGINIT
459
Optional Arguments
list-id
contains the identifier for an SCL list that contains image operation (IMGOP) and
image control (IMGCTRL) commands to pass to the function. The commands are
processed as the task starts. For command descriptions, see “Commands Used with
IMGCTRL” on page 457 and Appendix 1, “Commands Used with the IMGCTRL,
IMGOP and PICFILL Functions,” on page 795.
A value of zero means that no list is passed.
Type
Numeric or List
option
specifies a window option:
’NODISPLAY’
prevents the Image window from being created. This can be
useful in SCL programs that read, process, or write images
without displaying them.
’TOPWINDOW’
causes the Image window to stay on top of the FRAME or
SCL window when it is created.
Type
Character
Details
The IMGINIT function initializes the image environment. This usually means opening
the Image window, but you must use this function even if you plan to manipulate images
without displaying them.
When you initialize the Image window, the list that you pass to IMGINIT can include
commands to initialize the window size.
Example
Initialize the Image window size:
width=700;
height=520;
xpos=0;
ypos=0;
cmdid=makelist();
allcmdid=makelist();
rc=insertc(cmdid,’WSIZE’,-1);
rc=insertn(cmdid,width,-1);
rc=insertn(cmdid,height,-1);
rc=insertn(cmdid,xpos,-1);
rc=insertn(cmdid,ypos,-1);
rc=insertl(allcmdid,cmdid,-1);
taskid=imginit(allcmdid,’TOPWINDOW’);
Start the image task without displaying the Image window:
taskid=imginit(allcmdid,’nodisplay’);
460
Chapter 13
•
SAS Component Language Dictionary
IMGOP
Performs image operations
Category:
Image
Syntax
rc=IMGOP(task-id, command, <other arguments>);
Required Arguments
rc
contains the return code for the operation:
0
successful
>0
not successful
Type: Numeric
task-id
contains the identifier (returned by a previous IMGINIT function) of the task to be
operated upon.
Type: Numeric
command
the command to execute.
Type: Character
Optional Argument
other-arguments
lists arguments that are used for a command. The arguments required for a command
may include image file attributes. You can specify image file attributes by enclosing
the attributes in quotation marks and separating multiple attributes with blanks. For
example:
rc=imgop(tid,"WRITE",filename,
"FORMAT=TIFF
COMPRESS=G3FAX"):
Type: Character or Numeric
Details
Commands Used with IMGOP
For detailed information about these commands, see Appendix 1, “Commands Used with
the IMGCTRL, IMGOP and PICFILL Functions,” on page 795.
CONVERT
converts an image to the specified image type and depth.
IMGOP
461
COPY
copies an image.
CREATE_IMAGE
creates a new image that is stored in memory.
CROP
crops the selected image.
DESTROY
removes an image from memory and from the display.
DESTROY_ALL
removes all images from memory and from the display.
DITHER
dithers an image to a color map.
DITHER_BW
dithers the selected image to a monochrome black and white image.
EXECLIST
executes a list of commands.
FILTER
applies a filter to an image.
GAMMA
applies a gamma value to the selected image.
GENERATE_CMAP
generates a color map for the selected image.
GET_BARCODE
returns the value of the specified bar code.
GET_COLORS
returns the RGB values of the index positions of a color map for the selected image.
GET_PIXEL
returns the pixel value of a specified position in the selected image.
GRAB_CMAP
grabs the color map from the selected image.
MAP_COLORS
maps colors to the closest color in the selected color map.
MIRROR
mirrors an image.
NEGATE
changes the image to a negative.
PASTE
displays an image at a specified location.
PASTE_AUTO
displays an image automatically.
PRINT
prints an image.
QUANTIZE
reduces the number of colors used for an image.
462
Chapter 13
•
SAS Component Language Dictionary
QUERYC, QUERYL, and QUERYN
query information about images.
READ
reads an image from an external file, a SAS catalog, or a device.
READ_CLIPBOARD
reads an image from the host clipboard.
READ_PASTE
reads and displays an image.
READ_PASTE_AUTO
reads and automatically displays an image.
ROTATE
rotates an image clockwise by 90, 180, or 270 degrees.
SCALE
scales an image.
SELECT
selects the image identifier to be used in other commands.
SET_COLORS
assigns the RGB values for the index positions of a color map for the current image.
SET_PIXEL
assigns the pixel value in an image at the specified position.
STANDARD_CMAP
selects a color map.
THRESHOLD
converts color images to black and white, using the value that is specified with the
THRESHOLD command.
TILE
replicates the current image into a new image.
UNPASTE
removes an image from the display.
WRITE
writes an image to a file or to a SAS catalog.
WRITE_CLIPBOARD
writes an image to the host clipboard.
EPS Files
When read with IMGOP, Encapsulated Postscript Interchange (EPSI) files display as
low-resolution and monochrome. This degraded image is the preview version of the
actual image.
IMGTERM
Terminates an image task
Category:
Image
IMPORT (create a table)
Syntax
rc=IMGTERM(task-id);
Required Arguments
rc
contains the return code for the operation:
0
successful
>0
not successful
Type
Numeric
task-id
contains the identifier of the task, which was returned by a previous IMGINIT
function.
Type
Numeric
Example
IMGTERM used within the TERM section:
term:
if (task-id ne 0) then
rc=imgterm(task-id);
return;
IMPORT (create a table)
Creates a SAS table from an external file
Category:
SAS Table
Syntax
name=IMPORT(table-name, file <,’DEFINE’>);
Required Arguments
name
the name of the last SAS table that was created.
Type
Character
table-name
the new SAS table to create. If the table already exists, a warning message is
displayed when the IMPORT window opens.
Type
Character
463
464
Chapter 13
•
SAS Component Language Dictionary
file
the fileref or physical filename of the external file from which data are to be
imported. A physical filename must be enclosed in quotation marks. (See the
example.)
Type
Character
Optional Argument
DEFINE
specifies to open the DEFINE window before opening the IMPORT window.
Type
Character
Details
General Usage
CAUTION:
Blank lines in files can cause problems. Under some host operating systems, blank
lines in an external file may adversely affect the ability of the IMPORT function to
extract data from the file.
The IMPORT function returns the name of the last SAS table that it created from an
external data file. This function enables users to easily import raw data from an external
file into a SAS table.
Two auxiliary windows are associated with IMPORT: the IMPORT window and the
DEFINE window.
The IMPORT Window
The IMPORT window, which defines the columns for the SAS table, is the primary
window for the IMPORT function. The first two lines of the external file are displayed
below a ruler in order to help the application user identify the variables for the columns.
If numbers for start and end columns are not supplied, then list input is used, and items
in the file must be separated by at least one blank. Users can use the following fields in
the IMPORT window to specify information about the table columns:
Name
specifies the name for the table column. This can be any valid SAS name that is up
to 32 characters long.
Start/End Column
specifies the starting and ending columns of the value in the external file. These
fields are optional. You can specify a starting column without specifying an ending
column but not vice versa. If you omit the ending column, it is calculated to be one
less than the next starting column.
Type
specifies the data type of the table column. Choose the type by pressing ENTER or
clicking with the mouse on the appropriate type.
Format
specifies a SAS format. Enter a ’?’ to display a list of some common formats. This
field is optional.
IMPORT (create a table)
465
Informat
specifies a SAS informat. Enter a ’?’ to display a list of some common informats.
This field is optional.
Label
specifies a label for the table column. The label can be up to eight characters long.
This field is optional.
IMPORT Window Command Menu
The File menu enables you to perform save operations, to import data with the Import
Wizard, to export data using the Export Wizard, to perform print operations, to send
mail, and to close the window.
The Edit menu enables you to copy marked text, to select or deselect marked text, to set
the horizontal and vertical scroll amounts, to perform find operations, and to set the
keyfield (the field to search with the next Find command).
The View menu enables you to scroll right and left, to specify the sort order for fields in
the window, to display the first record in hexadecimal representation, and to open other
SAS windows.
The Tools menu enables you to specify conditions for querying values in the file, to
open a Viewtable window, and to run a session of graphics editors, the Report Editor or
Text Editor. You can also set a variety of options.
The Data menu enables you to create a SAS table from contents of the external file, to
test read the file, to define fields with the Define window, to specify a different external
file for input, to specify a new name for the SAS table to create, to display the length of
the longest record that has been read, to view the external file, and to edit or browse the
data set that was created from the external file.
The DEFINE Window
The DEFINE window is displayed when you use the DEFINE option with the IMPORT
function or when you select Data ð Define fields from the IMPORT window. It
displays the first line from the external file, along with a ruler and delimiter lines. On the
delimiter lines, you can use < and > to mark the beginning and end of a column,
respectively. If the column is only one character wide, use a vertical bar (|).
In order to use the DEFINE window, you must align the data values in columns in the
data records.
When you issue the END command to exit from this window, the fields are given default
column names and types (numeric or character). The IMPORT window then opens so
that you can change the column names and optionally add formats and informats.
Example
Create a new SAS table named MYLIB.NEW using data in the file to which the fileref
EXTERN has previously been assigned:
name=import(’mylib.new’,’extern’);
Create a new SAS table named MYLIB.NEW using data in the file with the physical
name SAMPLE1.DATA. The name of the file is enclosed in quotation marks to indicate
that a physical filename, not a fileref, is being passed to the IMPORT function.
name=import(’mylib.new’,"’sample1.data’");
Note: The form of the physical filename depends on the host operating system.
466
Chapter 13
•
SAS Component Language Dictionary
IMPORT
Defines a search path for references to CLASS entries
Category:
Catalog, Object Oriented
Syntax
IMPORT class-specification;
Required Argument
class-specification
is the two- to four-level name of a CLASS entry. If it is a four-level name, then that
CLASS entry is imported. If it is a two-level name, then it is used as the
libref.catalog prefix for any one- or two- level CLASS entry names in the program.
This prefix is concatenated to the one- or two-level CLASS entry name, and that is
the CLASS entry that is searched for. The first CLASS entry that is found is the one
that is imported. Any subsequent entries that are found are flagged as warnings.
Details
The IMPORT statement defines a search path for CLASS entry references in an SCL
program so that you can refer to CLASS entries with one- or two-level names instead of
having to use a four-level name in each reference. The current catalog is always the first
catalog to be searched for a one- or two-level class name, regardless of whether there are
any imported catalogs. References to CLASS entries are resolved by the SCL compiler
at compile time. The SEARCH function can be used to define a search path that will
resolve at run time.
Examples
Example 1: Defining a Search Path
Define a MYLIB.MYCAT as a search path for the program.
/* All the program's classes */
/* are defined in MYLIB.MYCAT *
IMPORT mylib.mycat;
/* collobj1 is defined in
*/
/* mylib.mycat.collection.class */
DECLARE Collection c1=_new_ Collection();
/* collobj2 is defined in
*/
/* mylib.mycat.OrderedCollection.class */
DECLARE OrderedCollection c2=_new_ OrderedCollection();
Example 2: Importing a Class from Another Catalog
This example imports class X from another catalog. Class Y is in the current catalog.
X.SCL
class work.cat.x;
public num n;
endclass;
INFORMAT 467
Y.SCL
import work.cat2;
class y;
m: method o: x;
o.n=99;
endmethod;
endclass;
Z.SCL
init:
import work.cat2;
dcl y yobj=_new_ y();
dcl x xobj=_new_ x();
yobj.m(xobj);
put xobj.n=;
return;
This example should produce the following output:
xobj.n=99
See Also
•
“DECLARE” on page 304
•
“SEARCH” on page 639
INFORMAT
Verifies that the specified informat is valid
Category:
Formatting
Syntax
rc=INFORMAT(informat,type);
Required Arguments
rc
contains the return code for the operation:
1
successful
0
not successful
Type: Numeric
informat
is an informat that is supplied by SAS or created using the FORMAT procedure. The
name of an informat must include a period (for example, date7. or comma10.2).
Type: Character
type
specifies the type of the informat:
'C'
character
468
Chapter 13
•
SAS Component Language Dictionary
'N'
numeric
Type: Character
Details
If the specified informat is not known to the SAS session, then the operation is
unsuccessful. The function verifies that valid widths are specified for informats.
See SAS Formats and Informats: Reference for details about informats.
Examples
Example 1: Verifying the Validity of a Character Informat
Verify that $MYFMT. is a valid character informat that has been defined for the current
SAS session. (The value returned to the variable RC is 1.)
rc=informat('$myfmt.','c');
Example 2: Verifying the Validity of a Numeric Informat
Verify that 5.6 is not a valid informat for numeric values. (The value returned to the
variable RC is 0.)
rc=informat('5.6','n');
See Also
“FORMAT” on page 405
INITROW
Initializes the Table Data Vector (TDV) for a SAS table to missing values
Category:
SAS Table
Syntax
rc=INITROW(table-id);
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
table-id
is the identifier that was assigned when the SAS table was opened.
Type: Numeric
INPUTC and INPUTN
469
Details
INITROW initializes the TDV to missing values. This prevents bad data from being
written to a table row when you do not explicitly assign values to columns with the
PUTVARC or PUTVARN function and you use the APPEND function with the
NOINIT option.
Example
Open the table whose name is saved in the variable TABLE, initialize a new row to
missing, and then write a value for the NAME column. When the new row is appended
to the data table, the column NAME is initialized to the value JOHN while values in all
other columns are set to missing.
tableid=open(table);
rc=initrow(tableid);
call putvarc(tableid,varnum(tableid,'name'),'JOHN');
rc=append(tableid,'noinit');
rc=close(tableid);
INPUTC and INPUTN
Read a character value using an informat
Category:
Formatting
Syntax
char-value=INPUTC(char-string,char-informat);
num-value=INPUTN(char-string,num-informat);
Required Arguments
char-value
contains char-string with the character informat applied to it.
Type: Character
num-value
contains char-string converted to a numeric value with the numeric informat applied
to it.
Type: Numeric
char-string
is the character string to be read.
Type: Character
char-informat
is the character informat to use for reading char-string.
Type: Character
num-informat
is the numeric informat to use for reading char-string.
Type: Numeric
470
Chapter 13
•
SAS Component Language Dictionary
Details
INPUTC and INPUTN both read a character value. However, INPUTC applies a
character informat and returns a character value, and INPUTN applies a numeric
informat and returns a numeric value. These functions are similar to the INPUT function
in the DATA step.
Note: Dot notation cannot be used with the INPUTC or INPUTN functions. This
restriction is necessary to allow proper parsing of the char-informat and numinformat parameters.
For more information about using an informat to read a value, see the INPUT function
for the DATA step in SAS Functions and CALL Routines: Reference.
Both the INPUTC function and the DATA step INPUT function that works in SCL, trim
trailing blanks from the returned value. If you want to retain trailing blank spaces, use
the PUT or PUTC functions.
Examples
Example 1: Using the INPUTC Function
Read the character variable NAME, using the $UPCASE3. informat:
name='sas';
cval=inputc(name,'$upcase3.');
put cval=;
This program produces the following output:
cval=SAS
Example 2: Using the INPUTN Function
Read the character variable AMOUNT, containing the value $20,000.00, into the
numeric variable SALARY, using the COMMA10.2 informat:
amount='$20,000.00';
informat='comma10.2';
salary=inputn(amount,informat);
put salary=;
This program produces the following output:
salary=20000
Example 3: Using INPUTN with a DATE Value
Read the value in DATE and apply the JULIAN8. informat:
date='90091';
ndate=inputn(date,'julian8.');
put ndate=;
This program produces the following output:
ndate=11048
Example 4: Comparison of Space Trimming
Demonstrate how INPUT and INPUTC trim trailing blanks.
main:
a=input('12345',$10.);
INSERTC, INSERTL, INSERTN, and INSERTO 471
b=inputc('12345','$10.');
put 'INPUT and INPUTC trim space.';
put a b 'End';
c=put('12345',$10.);
d=putc('12345','$10.');
put 'PUT and PUTC preserve spacing.';
put c d 'End';
return;
This program produces the following output:
INPUT and INPUTC trim space.
12345 12345 End
PUT and PUTC preserve spacing.
12345
12345
End
See Also
•
“PUT Function” in SAS Functions and CALL Routines: Reference
•
“PUTC and PUTN” on page 604
INSERTC, INSERTL, INSERTN, and INSERTO
Insert a value into an SCL list
Category:
List
Syntax
rc=INSERTC(list-id,cval<,index<,name> > );
rc=INSERTL(list-id,sublist-id<,index<,name > > );
rc=INSERTN(list-id,nval<,index<,name > > );
rc=INSERTO(list-id,object-id<,index<,name > > );
Required Arguments
rc
is the list-id, which is the identifier of the modified list.
Type: Numeric
list-id
is the identifier of the list into which to insert the item. An invalid list-id produces an
error condition.
Type: Numeric or List
cval
is the character value to insert into the list with INSERTC.
Type: Character
sublist-id
is the identifier of the sublist to insert into the list with INSERTL. An invalid sublistid produces an error condition.
472
Chapter 13
•
SAS Component Language Dictionary
Type: Numeric
nval
is the numeric value to insert into the list with INSERTN.
Type: Numeric
object-id
is the identifier of the object to insert into the list with INSERTO. An invalid objectid produces an error condition.
Type: Numeric or Object
Optional Arguments
index
is the position at which to insert the item into the list. The position can be specified
as a positive or negative number. By default, index is 1 (the first item). If index is a
positive number, then the item is at position index from the beginning of the list. If
index is a negative number, then the item is at position ABS(index) from the end of
the list. Index must be in the range [−(n+1),−1] or [1,n+1] where n is the length of
the list. An error condition results if the absolute value for index is zero or if it is
greater than the number of items in the list.
Type: Numeric
name
is the name to assign to the item. If name is omitted, a name is not assigned to the
item.
Type: Character
Details
The item is inserted such that after you insert an item at position index, you can retrieve
it from position index with any of these functions.
These functions do not make a copy of the list. The insertion is performed in place. You
can append an item to an SCL list of length n by inserting at index=n+1 or at index=−1.
Note: The return value of these functions is not used to indicate whether an error has
been detected. When an error occurs, the program simply halts.
An error condition results if
•
the list has any of the following attributes:
•
NOUPDATE
•
FIXEDLENGTH
•
CHARONLY, and you use an insert function other than INSERTC
•
NUMONLY, and you use an insert function other than INSERTN
•
SASNAMES, and name is omitted or is not a valid SAS name
•
NODUPNAMES, and name duplicates the name of a list item.
•
the absolute value for index is greater than 1 plus the number of items in the list or is
0.
•
you attempt to insert a local list into a global list with INSERTL.
INSERTC, INSERTL, INSERTN, and INSERTO 473
You can use HASATTR to check the attributes of a list or list item. To change attributes,
use SETLATTR.
Examples
Example 1: Using the INSERTC Function
Insert CANADA as the third item in the list:
listid=insertc(listid,'CANADA',3);
After this insertion, return the value that was third in the list before the insertion of
CANADA shifted the value from the third to the fourth position:
cval=getitemc(listid,4);
Example 2: Using the INSERTL Function
Insert the sublist NEWLIST as the third item from the end of the list:
listid=insertl(listid,newlist,-3);
Example 3: Using the INSERTN Function
Assume that the list MYLIST contains four items, named A, B, C, and D, with the values
1, 4, 9, and 16, respectively. Insert two new items: a string at the default position 1 (the
beginning of the list), and a number at position −1 (the end of the list). The new number
is given the name E.
call putlist(mylist,'Before: ',0);
mylist=insertc(mylist,'Squares');
mylist=insertn(mylist,25, -1,'E');
call putlist(mylist,'After: ',0);
This program produces the following output:
Before: (A=1
B=4
C=9
D=16
)[3]
After: ('Squares'
A=1
B=4
C=9
D=16
E=25
)[3]
Note: [3] is the list identifier that was assigned when this example was run and may be
different each time the example is run.
Example 4: Using the INSERTO Function
Create the list MYLIST, insert the item whose identifier is stored in the variable
MYOBJECT, and assign the name My Object to the item:
declare sashelp.fsp.object myobject = _new_ sashelp.fsp.object(),
list mylist;
mylist=makelist();
rc=inserto(mylist,myobject,-1,'My Object');
474
Chapter 13
•
SAS Component Language Dictionary
See Also
•
“GETITEMC, GETITEML, GETITEMN, and GETITEMO” on page 424
•
“GETNITEMC, GETNITEML, GETNITEMN, and GETNITEMO” on page 429
•
“POPC, POPL, POPN, and POPO” on page 592
•
“SETITEMC, SETITEML, SETITEMN, and SETITEMO” on page 657
•
“SETNITEMC, SETNITEML, SETNITEMN, and SETNITEMO” on page 667
INSTANCE
Creates an object and returns its identifier
Category:
Object Oriented
Syntax
object-id=INSTANCE(class-id <,arg>);
Required Arguments
object-id
contains the identifier that was assigned to the new object.
Type: Numeric or Object
class-id
the identifier for the class, which is returned by the LOADCLASS function.
Type: Numeric
Optional Argument
arg
is an argument to pass to the _init method.
Type: Numeric
Details
When creating an object (or instance) of a class, INSTANCE sends the _init method for
the specified class to the new instance and passes arg as an argument to the _init method.
If arg is not specified, then no argument is passed to the _init method. To indicate that
the numeric parameter is optional, the _init method of all classes should use the
OPTIONAL= option in the METHOD statement or ENTRY statement.
A common practice is to use an SCL list as arg. You can then pass an arbitrary list of
data which will be accessible in the _init method.
To delete an object that was created with INSTANCE, use its _term method. For
example:
dcl object objectid;
objectid=instance(classid);
objectid._term();
You cannot use the INSTANCE function to create instances of the Frame class.
INTERFACE 475
For more information about classes and methods, see the documentation for SAS/AF
classes.
Example
Load a class named Queue, a subclass of the Object class, and create two instances of
the Queue class. The Inqueue class is created with a maximum number of items. The
Outqueue class does not have a maximum.
queue=loadclass(’applib.classes.queue’);
inqueue=instance(queue, max_items);
outqueue=instance(queue);
Assume that the _init method of the Queue class is declared as
_init: method optional= maxItems 8;
...more SCL statements...
endmethod;
See Also
•
“APPLY” on page 219
•
“ENTRY” on page 346
•
“LOADRES” on page 518
•
“METHOD (define)” on page 535
•
“_NEO_” on page 557
•
“SEND” on page 649
•
“SUPAPPLY” on page 686
•
“SUPER” on page 688
INTERFACE
Defines a group of abstract methods shared by the related classes
Category:
Object Oriented
Syntax
INTERFACE interface-name
<EXTENDS interface-name>
</ (interface-optional-clause)> ;
<limited-method-declaration-statements>
ENDINTERFACE;
Required Arguments
interface-name
is the name of the interface that you are defining, which can be specified as a one- to
four-level name. The entry type is INTERFACE.
476
Chapter 13
•
SAS Component Language Dictionary
EXTENDS-interface-name
specifies the parent interfaces as a one- to four-level name. An interface can inherit
from parent interfaces. If you do not use the EXTENDS clause, the parent-interface
defaults to SAS HELP.FSP.INTRFACE.CLASS.
interface-optional-clause
specifies options for the interface. You must put the list inside the parentheses that
follow a / (slash). Separate multiple options with commas. The only option currently
supported is
Description = description
is a description of the INTERFACE entry.
Optional Arguments
limited-method-declaration-statements
defines the interface methods. Declare the methods as follows:
method-label-name: METHOD
<argument-list><OPTIONAL=argument-list></(method-options)>;
method-label-name
can be up to 32 characters and has the same restrictions as an SCL label.
argument-list
list one or more sets of arguments, with each set specified as follows:
var-list <:INPUT|UPDATE|OUTPUT>:data-type(length)
var-list
lists one or more variables to contain values that are passed in from a method
call using either dot notation or the METHOD, SEND, SUPER, APPLY or
SUPAPPLY routine or function. Variables can also be reference arrays.
Reference array dimensions are specified by '*'. Use commas to separate '*'
for multiple dimensions. The actual size of the reference array will be
determined at run time based on the dimensions specified in the array
parameter of the calling method. For more information, see “ARRAY” on
page 220 and “Example 3: Reference Array Whose Size Is Determined at
Run Time” on page 541.
INPUT | I
specifies that, at run time, the variable contains the value that is copied from
the corresponding parameter of the calling method. However, when the
program finishes, the value is not copied back to the calling method.
UPDATE | U
specifies that, at run time, the variable contains the value that is copied from
the corresponding parameter of the calling method. When the program
finishes, the value is copied back to that parameter.
OUTPUT | O
specifies that, when the program finishes, the value is copied back to the
corresponding parameter in the calling program. An error condition results if
the corresponding parameter in the calling program is a constant, because a
constant cannot receive a value.
data-type
specifies the type of data that the variable will contain. A named data type
(for example, CHAR or LIST) must be preceded by the : delimiter. The
delimiter is optional for unnamed data types (for example, $).
INTERFACE 477
CHAR<(length)>
specifies that the variable will contain character data. Length can be 1 to
32,767 characters. If length is not provided, the default length is 200.
LIST
specifies that the variable will contain an SCL list identifier.
NUM
specifies that the variable will contain a numeric value.
OBJECT
specifies that the variable will contain the identifier for an object when it
is defined at run time.
This type causes the SCL compiler to generate extra conversion
instructions. Consequently, you should use it only when necessary so as
to achieve optimal run-time performance.
class-name
specifies that the variable will contain the identifier for an object of the
class specified in class-name. Class-name must be a three- or four-level
name unless an IMPORT statement has specified the libref and catalog.
In that case, the name can be a one- to four-level name. If the entry type
is not specified, it is assumed to be CLASS.
interface-name
specifies that the variable will contain the identifier for an object of the
class that supports the interface specified in interface-name. Interfacename must be a three– or four-level name unless an IMPORT statement
has been used to specify the libref and catalog. In that case, the name can
be a one- to four-level name.
If the entry type is not specified and a class with that name does not exist,
the default entry type of INTRFACE is assumed.
To be compatible with the applications built in earlier releases of SAS software,
the : delimiter is optional for variables that have been declared with unnamed
data types (for example, $), but it is required for variables that have been
assigned named data types. The following example shows a variety of data type
declarations, including reference arrays that use * as the dimensions:
mymethod: method
char1 : Char(20)
char2 : Char(10)
char3 :input :char(50)
charArr(*):u:char /* a reference array */
num1
: num
num2
: num
num3
: num
numArr(*):num
/* a reference array */
myList :list
myObj :object
myCol :Sashelp.Fsp.Collection.class ;
Type: Character
length
is a numeric constant that specifies the length of the preceding variable or
variables. The length of a character variable does not have to match the length of
the corresponding passed parameter. SCL pads or truncates as necessary. When a
478
Chapter 13
•
SAS Component Language Dictionary
length is specified for a variable that is declared as CHAR, the length
specification must be enclosed in parentheses.
Type: Character
OPTIONAL=
enables you to specify one or more optional arguments that are used only if the
calling program supplies the corresponding parameters in the parameter list of the
calling routine. If corresponding parameters are not supplied, then the optional
arguments are initialized to missing values.
method-options
specify options for an interface method. You must put the list inside parentheses that
follow a / (slash). The only option currently supported is Description = description,
which may be used to provide a description of the method.
Details
In order to group related classes which share similar method names, a superclass can be
created. One approach to create the superclass is to use the INTERFACE block. You can
use the INTERFACE and ENDINTERFACE statements to create an INTERFACE block
that contains method definitions. Method implementations are not allowed in the
INTERFACE block, so all methods are defined as abstract methods.
Interfaces describe “contracts” in a pure, abstract form, but an interface is interesting
only if a class supports it. Any class that supports an interface must implement all of the
methods defined in the interface. Since the INTERFACE block does not contain any
method implementations, class developers can use the INTERFACE block to reflect the
high-level design of their applications. Any class can also be specified with the
“required” interface using the “Required-Clause”. The SCL compiler will generate
information that will be used to validate whether the actual method used at run time
matches the required interface.
To create an interface from an SCL entry that contains an INTERFACE block, you must
issue either the SAVECLASS command or from FILE menu Save Class Pmenu. This
compiles the entry and creates the INTERFACE entry that is specified by interfacename. This is equivalent to using the Interface Editor to interactively create an
INTERFACE entry. However, the Interface Editor provides a tabular view of the
interface, whereas the INTERFACE statement in SCL provides a language view of the
interface. For maintenance purposes, the existing INTERFACE entry can also be
converted to SCL syntax by using the CREATESCL function. For more detailed
information, see “CREATESCL” on page 289.
Examples
Example 1: Defining a Simple Interface
The following INTERFACE block defines a simple myWidget interface with four GUI
methods.
interface work.a.myWidget.intrface;
refresh: method;
needRefresh: method;
select: method;
tab: method n1:NUM n2:NUM;
endinterface;
The following INTERFACE block defines an I/O interface with two I/O methods.
interface work.a.myIO.
INTERFACE 479
interface;
read: method string buffer;
write: method string buffer;
endinterface;
Example 2: Defining Classes That Support Interfaces
The INTERFACE blocks cannot contain method implementations, so any class that
supports an interface must implement all of the methods defined in the interface. The
following class implements methods that are defined in work.a.myIO.intrface:
class work.a.model.class supports work.a.myIO.intrface;
read: method string buffer
/ (scl='work.a.model.scl');
write: method string buffer
/ (scl='work.a.model.scl');
/* The following method is not in the interface */
myMethod: method n:Num
/ (scl='work.a.myscl.scl');
endclass;
The following class supports both the myWidget interface and the myIO interface.
class work.a.modelViewer.class
supports work.a.myWidget.intrface,
work.a.myIO.intrface;
refresh: method / (scl='work.a.mv.scl');
needRefresh: method / (scl='work.a.mv.scl');
select: method / (scl='work.a.mv.scl');
tab: method n1:NUM n2:NUM
/ (scl='work.a.mv.scl');
read: method string buffer
/ (scl='work.a.model.scl');
write: method string buffer
/ (scl='work.a.model.scl');
myMethod: method n: num
/ (scl='work.a.myscl.scl');
endclass;
Example 3: Defining Classes That Require Interfaces
The following class requires both the myWidget interface and the myIO interface. By
specifying which interfaces are required, you allow the SCL compiler to generate
information that will be used to validate whether the actual methods used at run time
matched the required interface.
class work.a.myRequired.class
Requires work.a.myWidget.intrface,
work.a.myIO.intrface;
...Other implementations...
endClass;
See Also
“CLASS” on page 249
480
Chapter 13
•
SAS Component Language Dictionary
IOPTION
Returns options for index columns and key columns
Category:
SAS Table
Syntax
options=IOPTION(table-id,key-name);
Required Arguments
options
contains options for the specified index key-name, separated by a blank:
MISSING
The index can contain missing values.
NOMISS
The index does not contain missing values.
NONUNIQUE
The index can contain non-unique values.
UNIQUE
The index contains only unique values.
Type: Character
table-id
is the identifier that was assigned when the table was opened. If table-id is invalid,
the program halts.
Type: Numeric
key-name
is the name of an index key.
Type: Character
Details
An index is an auxiliary data structure used to speed up the selection of records that are
specified by the value of a column.
You can create indexes using
•
the ICREATE function in SCL
•
the DATASETS and SQL procedures in Base SAS software
•
SAS/IML software
•
the CONTENTS function in SCL
•
the ACCESS procedure in SAS/ACCESS software.
When an error occurs, IOPTION returns a blank string.
ISACTIVE
481
Example
Return the options of the defined key index ITEMTYPE for the SAS table
WORK.DATAONE. If the value returned to the OPTIONS column is blank, then the
message returned by the SYSMSG function is displayed on the message line.
tableid=open('work.invoice','i');
options=ioption(tableid,'itemtype');
if (options=' ') then _msg_=sysmsg();
See Also
•
“CONTENTS” on page 271
•
“ICREATE” on page 451
•
“IDELETE” on page 455
•
“ISINDEX” on page 483
•
“IVARLIST” on page 488
ISACTIVE
Returns the number of the active button in a radio box or check box or the active station in a choice group
Category:
Control or Field
Syntax
station=ISACTIVE(var-name<,row> );
Required Arguments
station
contains the status of a selection:
>0
the number of the button or station that is active
0
no button or station is active
Type: Numeric
var-name
is the radio or choice group to be tested.
Type: Character
Optional Argument
row
is the row number when the button or choice group is in the scrollable section of an
extended table in a PROGRAM entry. Do not specify row in programs for FRAME
entries. Specify row only when you want to check the active station from outside the
extended table's getrow or putrow section.
Type: Numeric
482
Chapter 13
•
SAS Component Language Dictionary
Details
You cannot use ISACTIVE in FSEDIT or FSVIEW programs.
Window controls can also use the _isActive method.
Example
Suppose your application has a radio box named HOBBY in which the third button
displays the value TENNIS. Branch to an appropriate program when a user selects the
TENNIS station (either by pressing ENTER or by clicking the mouse button).
if (isactive('hobby')=3)
then call display('tennis.frame');
See Also
•
“ACTIVATE” on page 215
•
“GRAY” on page 441
•
“ISGRAY” on page 482
•
“UNGRAY” on page 700
ISGRAY
Reports whether a FRAME entry control or choice group is grayed
Category:
Control or Field
Syntax
rc=ISGRAY(var-name<,station<,row> > );
Required Arguments
rc
contains the return code for the operation:
1
the specified station is grayed
0
the specified station is not grayed, or no station in the choice group is
grayed
m
the number of stations that are grayed, when an entire choice group is not
grayed
−n
the total number of stations, when an entire choice group is grayed.
Type: Numeric
var-name
is the window control or choice group to be tested.
Type: Character
ISINDEX
483
Optional Arguments
station
is the number of the choice group station or the button in a radio box. Station must
be greater than 0 and must be no greater than the total number of buttons in a radio
box or the number of stations in a choice group.
Type: Numeric
row
is the number of the row when the control or choice group is in the scrollable section
of an extended table. Row is valid for PROGRAM entries. Specify row only when
you want to determine whether the station is gray from outside the extended table's
getrow or putrow section.
Type: Numeric
Details
Window controls can also use the _isGray method.
Because choice groups can be defined only in SAS/AF software, you cannot use
ISGRAY in FSEDIT or FSVIEW programs.
Examples
Example 1: Determining Whether an Extended Table Row Is Grayed
Test whether the choice group WINE at the third row of an extended table is grayed:
if (isgray('wine',0,3)) then
do;
...SCL program statements...
end;
Example 2: Finding the Number of Stations in a Choice Group
Find out how many stations are defined for a choice group:
rc=gray('wine');
total=abs(isgray('wine'));
See Also
•
“ACTIVATE” on page 215
•
“GRAY” on page 441
•
“ISACTIVE” on page 481
•
“UNGRAY” on page 700
ISINDEX
Returns the type of index for a SAS table column
Category:
SAS Table
484
Chapter 13
•
SAS Component Language Dictionary
Syntax
index=ISINDEX(table-id,col-name);
Required Arguments
index
contains the type of the index:
(blank)
No index has been created for the specified column.
BOTH
The column is a member of both simple and composite indexes.
COMP
The column is a member of a composite index.
REG
The column is a regular (simple) index.
Type: Character
table-id
is the identifier that was assigned when the table was opened. If table-id is invalid,
the program halts.
Type: Numeric
col-name
is the name of a column in the SAS table. If col-name is not a column in the table,
then ISINDEX returns a blank value.
Type: Character
Details
An index is an auxiliary data structure used to assist in the location (that is, selection) of
rows that are specified by the value of a column. An index is called a simple index if it
contains the value of only one column. A composite index merges the values for more
than one column to form a single value. A given SAS table can have multiple simple
indexes, composite indexes, or any combination of these.
You can create indexes using
•
the ICREATE function in SCL
•
the DATASETS and SQL procedures in Base SAS software
•
SAS/IML software
•
the CONTENTS function in SCL
•
the ACCESS procedure of SAS/ACCESS software.
Example
Return the type of index for the FNAME column in the SAS table WORK.DATAONE:
dsid=open('work.dataone','i');
ixtype=isindex(dsid,'fname');
ISSEL
485
See Also
•
“CONTENTS” on page 271
•
“ICREATE” on page 451
•
“IDELETE” on page 455
•
“IOPTION” on page 480
•
“IVARLIST” on page 488
ISSEL
Returns the selection number for a specified row of a selection list
Category:
Extended Table
Syntax
selection=ISSEL(row);
Required Arguments
selection
contains the row's selection number, or 0 if the row is not selected.
Type: Numeric
row
is the number of the row that is being queried.
Type: Numeric
Details
You can use the ISSEL function in two ways:
•
to determine the order in which a certain row was selected
•
to determine whether a row is being selected or deselected.
Because you can define extended tables only with SAS/AF software, you cannot use
ISSEL in FSEDIT or FSVIEW programs. ISSEL is valid only for PROGRAM entries.
Window controls must use the _issel method.
In order for an extended table to be considered a selection list, you must specify a
number of selections in the SETROW routine.
Example
Suppose that your application has a selection list with ten rows and that the user has just
selected row 3 and then row 5. If ISSEL is called with the row argument equal to 5, then
the value 2 is returned for selection, because row 5 was the second selection.
You can also use ISSEL in the putrow section of an extended table application to test
whether a row is selected. Call the function for the desired row and check the selection
value to see whether its value is positive (the row has been selected) or zero (the row has
been deselected):
486
Chapter 13
•
SAS Component Language Dictionary
PUTROW:
if (issel(_CURROW_)) then
do;
...SCL statements to process the selected row...
end;
else
do;
...SCL statements to process the deselected row...
end;
return;
See Also
•
“NSELECT” on page 570
•
“SELECT (execute a statement)” on page 644
•
“SELECTED” on page 647
•
“UNSELECT” on page 704
ITEM
Specifies the classes on the server that can be accessed by applications on the client
Category:
Object Oriented
Syntax
ITEM class-name;
Required Argument
class-name
is the name of a class that you want included in the class package that you are
defining. The class name is a one- to four-level name of the form
library.catalog.member.CLASS.
Details
ITEM statements define the classes on the server whose methods and attributes can be
accessed by applications on the client.
See Also
“PACKAGE” on page 583
ITEMTYPE
Reports the type of an item in an SCL list
Category:
List
ITEMTYPE
487
Syntax
type=ITEMTYPE(list-id<,index> );
Required Arguments
type
contains the type of the specified item:
C
The item is a character item.
N
The item is a numeric item.
L
The item is a sublist item.
O
The item is a component item.Type: Character
list-id
is the identifier of the list containing the item whose type is returned by ITEMTYPE.
An invalid list-id produces an error condition.
Type: Numeric or List
Optional Argument
index
is the position of the item in the list. The position can be specified as a positive or
negative number. By default, index is 1 (the first item). If index is a positive number,
then the item is at position index from the beginning of the list. If index is a negative
number, then the item is at position ABS(index) from the end of the list. An error
condition results if the absolute value for index is zero or if it is greater than the
number of items in the list.
Type: Numeric
Details
An item's type depends on which function was used to create the item:
C (character) items
are created by SETITEMC, SETNITEMC, INSERTC.
N (numeric) items
are created by SETITEMN, SETNITEMN, INSERTN, MAKELIST, MAKENLIST.
L (sublist) items
are created by SETITEML, SETNITEML, INSERTL.
O (component) items
are created by SETITEMO, SETNITEMO, INSERTO.
See Also
•
“INSERTC, INSERTL, INSERTN, and INSERTO” on page 471
•
“MAKELIST” on page 527
•
“MAKENLIST” on page 528
•
“SETITEMC, SETITEML, SETITEMN, and SETITEMO” on page 657
•
“SETNITEMC, SETNITEML, SETNITEMN, and SETNITEMO” on page 667
488
Chapter 13
•
SAS Component Language Dictionary
IVARLIST
Returns the column names for an index key
Category:
SAS Table
Syntax
varlist=IVARLIST(table-id,key-name);
Required Arguments
varlist
contains one or more index columns (separated by a blank) for the specified key, or a
blank if key-name is invalid.
Type: Character
table-id
contains the identifier that was assigned when the table was opened. If table-id is
invalid, the program halts.
Type: Numeric
key-name
is the name of an index key.
Type: Character
Details
An index is an auxiliary data structure used to speed up the selection of records that are
specified by the value of a column.
An index is called a simple index if it contains the value of only one column. A
composite index merges the values for more than one column to form a single value. A
given SAS table can have multiple simple indexes, composite indexes, or a combination
of these.
You can create indexes using
•
the ICREATE function in SCL
•
the DATASETS and SQL procedures in Base SAS software
•
SAS/IML software
•
the CONTENTS function in SCL
•
the ACCESS procedure of SAS/ACCESS software.
Note: Because some engines now support mixed-case filenames, IVARLIST now
retains the cases of the returned selected items. If your application contains code that
assumes that the returned selection is in uppercase, your application may fail. You
may need to modify your application. For example, you can use the UPCASE
function to convert the returned selection to uppercase:
if (upcase(ivarlist(dsid, 'TESTNDX'))='NDXVAR'
If the application cannot be modified, you may need to specify the
VALIDVARNAME=V6 system option when you run the application to ensure that
KEYCOUNT
489
the selections returned from the IVARLIST function are in uppercase. For
documentation for the UPCASE function, refer to SAS Functions and CALL
Routines: Reference.
Example
Return the column list that is indexed for the key ITEMTYPE in the SAS table
MYLIB.DATAONE. Assume that ITEMTYPE is a simple index (that is, it contains the
values of only one column). The returned VARLIST contains the string ITEMTYPE.
tableid=open('mylib.dataone','i');
varlist=ivarlist(tableid,'itemtype');
See Also
•
“ICREATE” on page 451
•
“IDELETE” on page 455
•
“IOPTION” on page 480
•
“ISINDEX” on page 483
KEYCOUNT
Returns the number of rows that meet the criteria specified by an index key
Category:
SAS Table
Syntax
nrow=KEYCOUNT(table-id);
Required Arguments
nrow
contains the number of rows that meet the criteria, or <0 if an error occurred. The
error message can be retrieved by using SYSMSG.
Type: Numeric
table-id
is the identifier that was assigned when the table was opened. If table-id is invalid,
the program halts.
Type: Numeric
Details
KEYCOUNT returns the number of rows that meet the criteria specified by the index
key column. The index key column was specified with the last SETKEY function that
was used on the table. After KEYCOUNT executes, the table points to the first row that
meets the criteria defined by the last SETKEY function. Use FETCH or FETCHOBS to
read the row.
CAUTION:
490
Chapter 13
•
SAS Component Language Dictionary
Using KEYCOUNT with composite keys may show a larger number of rows
matching the search criteria than you expect. Using a composite key with
SETKEY operates the same way as the WHERE function only when the condition is
EQ. The value returned when the condition is EQ is the same as if the columns
specified in the composite key are connected by WHERE conditions using AND or
ALSO. (See Example 1.) For all other conditions (GT, GE, LT, or LE) specified with
SETKEY for a composite key, the composite key columns are concatenated to form
the index key. The number that the KEYCOUNT function returns is the number of
rows in the table that satisfy the composite key. For example, if the composite index
consists of columns GENDER and AGE and the condition is GT (greater than), the
values to search for are concatenated such that key values of F for GENDER and 13
for AGE yield an index key of F13. Because the search is performed on the
concatenated values, some values that you did not expect may meet the search
condition . For example, key values of M for GENDER and 11 for AGE meet the
search condition, because the string M11 is considered greater than the string F13.
(See Example 2.)
Examples
Example 1: Using a Simple Index Key
Suppose you have the following examples which use rows from the WORK.CLASS
table. Create a simple index for the table WORK.CLASS, using ICREATE or the
DATASETS procedure, with AGE as the index column. Also, create a composite index
for WORK.CLASS called COMP that consists of columns GENDER and AGE.
Set up a search criteria of AGE=13. SETKEY specifies that the key column is AGE and
the condition is equality.
/*
Locate rows where 'age = 13' */
tableid = open( 'work.class', 'v' );
/* Create the simple index */
rc = icreate(tableid,'age');
name = ''; gender = '';
age = 13;
call set(tableid);
rc = setkey(tableid,'age','eq');
nrow = keycount(tableid);
if (nrow < 0) then _msg_ = sysmsg();
else
do;
put 'Number of rows found:' nrow;
do while (fetch(tableid) ne -1);
put name= gender= age=;
end;
end;
This program produces the following output:
Number of rows found: 3
name=Alice gender=F age=13
name=Becka gender=F age=13
name=Jeffery gender=M age=13
KEYCOUNT
491
Example 2: Using a Composite Index Key with Condition 'EQ'
Set up search criteria of GENDER=F and AGE=13. SETKEY specifies that the key is
named COMP and the condition for the search is equality.
/* Locate rows where 'gender="F"' */
/* and 'age=13' */
tableid = open( 'work.class', 'v' );
/* Create index */
rc = icreate(tableid,'comp','gender age');
name = ''; gender = 'F'; age = 13;
call set(tableid);
rc = setkey(tableid,'comp','eq');
nrow = keycount(tableid);
if (nrow < 0) then _msg_ = sysmsg();
else
do;
put 'Number of rows found:' nrow;
do while (fetch(tableid) ne -1);
put name= gender= age=;
end;
end;
This program produces the following output:
Number of rows found: 2
name=Alice gender=F age=13
name=Becka gender=F age=13
Example 3: Using a Composite Index Key with Condition 'GT'
Set up search criteria of GENDER=F and AGE greater than 13. SETKEY specifies that
the key is named COMP and the condition for the search is greater-than. This example
illustrates the unexpected results returned by KEYCOUNT when you use composite
index keys and SETKEY using a 'GT' argument.
/*
Locate rows where 'genderage' > 'F13' */
tableid = open( 'work.class', 'v' );
/* Create index */
rc=icreate(tableid,'comp','gender age');
name = ''; gender = 'F'; age = 13;
call set(tableid);
rc = setkey(tableid,'comp','gt');
nrow = keycount( tableid);
if (nrow < 0) then _msg_ = sysmsg();
else
do;
put 'Number of rows found:' nrow;
do while (fetch(tableid) ne -1);
put name= gender= age=;
end;
end;
This program lists 14 rows from the indexed table that met the search criteria of
GENDER||AGE>=F13.
Number of rows found: 14
name=Gail gender=F age=14
name=Tammy gender=F age=14
name=Mary gender=F age=15
492
Chapter 13
•
SAS Component Language Dictionary
name=Sharon gender=F age=15
name=Thomas gender=M age=11
name=James gender=M age=12
name=John gender=M age=12
name=Robert gender=M age=12
name=Jeffrey gender=M age=13
name=Alfred gender=M age=14
name=Duke gender=M age=14
name=Guido gender=M age=15
name=William gender=M age=15
name=Philip gender=M age=16
You can see that James at AGE=12 does not meet the SETKEY requirement of AGE >
13 and GENDER > 'F'. However, his row was selected because the values were
concatenated before the comparison was made.
See Also
“SETKEY” on page 659
LASTCMD
Returns the text of the last command that was issued from the application window
Category:
Command
Syntax
cmdtext=LASTCMD();
Required Argument
cmdtext
contains the text of the last command that was issued from the application window.
Type: Character
Details
If the command contains multiple words, only the first word is returned.
LASTCMD is usually used in conjunction with CONTROL ENTER, ALWAYS, or
ALLCMDS.
Example
Retrieve the last command that was issued in the window and display a message, based
on that command name:
INIT:
control always;
return;
MAIN:
cmd=lastcmd();
if cmd='GO' then
_msg_='Last command was '||cmd;
LASTKEY
493
return;
See Also
“WORD” on page 734
LASTKEY
Returns the number of the last function key that was pressed from the application window
Category:
Keys
Syntax
keynum=LASTKEY();
Required Argument
keynum
contains the number of the function key that was pressed from the application
window, or 0 if ENTER was pressed.
Type: Numeric
Details
The returned value is the ordinal position of the key definition in the KEYS window. In
order for this function to work, you must have a window variable or text in the
DISPLAY window.
To retrieve the name of the last function key pressed by a user, use FKEYNAME.
LASTKEY is used in conjunction with CONTROL ENTER, ALWAYS, and
ALLCMDS. LASTKEY does not retrieve the number of a function key that has a global
command assigned to it.
Example
Return the number of the last function key that a user pressed. (This example requires a
window with at least one window variable.)
INIT:
control enter;
return;
MAIN:
keynum=lastkey();
if (keynum ne 0) then
put 'Last function key is ' keynum;
else
put 'Last function key is not defined
or the ENTER key was pressed';
return;
See Also
•
“FKEYNAME” on page 394
494
Chapter 13
•
SAS Component Language Dictionary
•
“GETFKEY” on page 423
•
“SETFKEY” on page 654
•
“CONTROL” on page 274
LEAVE
Stops processing the current DO group or DO loop and resumes with the next statement in sequence
Category:
Note:
Control Flow
SAS Statement with limitations in SCL
Syntax
LEAVE <label> ;
Optional Argument
label
is the name of a program label that is associated with the DO group.
Type: Character
Details
The LEAVE statement is provided in SCL to control the execution of DO groups. When
you need to force the statements in a DO group to stop executing, you can use the
LEAVE statement to stop executing statements in a DO group and to start executing a
statement that is outside of that DO group.
Note: In DATA step code, the LEAVE statement stops processing only the current DO
loop. In SCL code, the LEAVE statement stops processing the current DO loop or
DO group, whichever is closest. For example, suppose your code contains a DO loop
that contains DO groups:
do n=1 to 5;
/* DO loop */
if n=3 then do; leave; end;
put n=;
end;
/* DO group */
When this code is compiled and run as part of an SCL program, the output is:
n=1
n=2
n=3
n=4
n=5
When this code is submitted as part of a DATA step, the output is:
n=1
n=2
n=3
See “DO” on page 333 for more information on DO groups and DO loops.
For details about the LEAVE statement in the Base SAS language, see the “LEAVE
Statement” in SAS Statements: Reference.
LEAVE 495
Examples
Example 1: LEAVE Statements Without Label Names
If a LEAVE statement does not contain the name of a program label, the program stops
executing the statements in the DO group and starts executing the first statement after
the DO group's END statement. For example, when the condition in the IF statement in
the following program is true (that is, when the value of SUM > 10), the program jumps
immediately to the statement following the END statement (in this case, the PUT
statement).
INIT:
return;
MAIN:
do while(i<5);
sum+i;
i=i+2;
if (sum>10) then
do;
leave;
end;
put sum=;
end;
totalsum=sum;
return;
TERM:
return;
Example 2: LEAVE Statements With Label Names
In this example, when the condition SUM > 50 is true, the program leaves the LAB1 DO
group and returns to the next statement following the DO group (in this case, the PUT
statement).
INIT:
sum=45;
return;
MAIN:
link LAB1;
return;
LAB1:
do i=1 to 10;
if (sum>10) then do;
k=0;
do until (k>=20);
sum+k;
if (sum>50) then leave LAB1;
k+2;
end;
end;
end;
put 'LEAVE LAB1, sum >50 ' sum=;
return;
TERM:
return;
496
Chapter 13
•
SAS Component Language Dictionary
See Also
•
“CONTINUE” on page 272
•
“DO” on page 333
LEFT
Returns a left-aligned character string
Category:
Character
Syntax
lstring=LEFT(string<,length> );
Required Arguments
lstring
contains the left-aligned character string. If lstring already exists, then specifying a
length in the LEFT function affects the current length of lstring only if the specified
length is less than the trimmed length of the string.
Type: Character
string
is the character string to be left-justified.
Type: Character
Optional Argument
length
is the length in which the character string is to be left-justified. The default is the
maximum length of lstring.
Type: Numeric
Details
Any leading blanks in the string are removed so that the first character in the string is
nonblank. The default length of the returned value is the trimmed length of the leftaligned string. Use length to specify a different maximum length for the returned string.
In order for LEFT to work properly when lstring is a window variable, set the
justification field (JUST) in the field attribute window for lstring to NONE.
To right-justify a character string, use RIGHT. To center a character string, use
CENTER.
See Also
•
“RIGHT” on page 623
•
“CENTER” on page 246
LEGEND
497
LEGEND
Displays a legend window or refreshes the current LEGEND window
Category:
Legend
Syntax
CALL LEGEND(<window-name<,back-color<,border-color<,border-attr> > > > );
Optional Arguments
window-name
is the name that is displayed in the window border. Once assigned, a window name is
displayed on subsequent legend windows until it is changed by another LEGEND
routine that assigns a different name or that assigns a null string ('') to delete the
name from the current legend window.
Type: Character
back-color
is a background color name, or '' for the default color. Available colors are
BLACK, BLUE, BROWN, CYAN, GRAY, GREEN, MAGENTA, ORANGE,
PINK, RED, WHITE, and YELLOW. SASCOLOR window elements can also be
used.
The default background color is the SASCOLOR window element "Secondary
Background."
Type: Character
border-color
is a border color name, or '' for the default color. Available colors are listed under
back-color. SASCOLOR window elements can also be used for border-color.
The default border color is the SASCOLOR window element "Secondary Border."
Type: Character
border-attr
is a border attribute, or '' for the default attribute. Attributes are NONE,
BLINKING, HIGHLIGHT, HIREV, REVERSE, and UNDERLINE. If you specify a
SASCOLOR window element for border-color, then border-attr is ignored, because
the SASCOLOR window element contains a display attribute.
The default border attribute is the SASCOLOR window element "Secondary
Border".
Type: Character
Details
The LEGEND routine displays legend text that has been previously specified with the
PUTLEGEND routine. You can specify any combination of optional arguments for
LEGEND.
By default, the LEGEND window has the following characteristics:
498
Chapter 13
•
SAS Component Language Dictionary
•
The window occupies rows 1 through 6 and columns 1 through the width of the
display device.
•
The window name is either the name that was specified by the last LEGEND routine
or the name of the current legend window.
Before invoking the LEGEND routine, you may need to resize the associated application
window so that it does not obscure the LEGEND window. To do this, either use the
WDEF routine or assign a new size to the window.
Additionally, you can specify a size for a legend window by using the WREGION
routine before calling the legend.
Example
Suppose you have two FRAME entries, X and Y. Assume that X.FRAME contains two
pushbuttons named PUSHPOP and ENDLGND, and that X.SCL contains the
corresponding control labels. When the PUSHPOP button is activated, the
PUSHLEGEND call will save X's legend, and the Y.FRAME will be displayed. Y will
then set up and display its own legend. After the return from Y, the POPLEGEND call
will restore X's legend.
If the ENDLGND button is activated, ENDLEGEND will close the LEGEND window,
and the application window will be restored to its original size.
X.SCL contains the following program:
INIT:
/* Get the number of rows and columns for later */
/* use.
*/
nr = winfo('numrows');
nc = winfo('numcols');
/* Resize the application window to */
/* start at row 10. */
call wdef(10, 1, nr-9, nc);
/* Set the size of the LEGEND window - row 1 */
/* through row 9. Pass a null string */
/* as the fifth parameter to indicate */
/* that the LEGEND window has no
*/
/* command area.
*/
call wregion(1, 1, 9, nc, '');
/* Set up the legend text and display it. */
call putlegend(1,'This is line one of the legend for X',
'yellow','none');
call putlegend(2,'This is line two of the legend for X',
'yellow','none');
call legend('Sample LEGEND Window for X',
'gray','blue');
return;
MAIN:
return;
/* PUSHPOP label. If this is executed, */
/* we'll save the current */
/* legend and call y, */
/* which will display its own legend. */
PUSHPOP:
/* Push and call. */
call pushlegend();
LENGTH (return string length)
call display('y.frame');
/* Restore the original legend. */
call poplegend();
return;
/* ENDLGND label. If this is executed,
/* the LEGEND window will be
/* closed, and the application window
/* will be restored to its original size.
ENDLGND:
call endlegend();
call wdef(1, 1, nr, nc);
return;
TERM:
return;
*/
*/
*/
*/
Y.SCL contains the following program:
INIT:
/* Set up and display Y's own */
/* LEGEND window. */
nr = winfo('numrows');
nc = winfo('numcols');
call wdef(10, 1, nr-9, nc);
call wregion(1, 1, 9, nc, '');
call putlegend(1,'This is line one of the legend for Y',
'yellow', 'none');
call putlegend(2,'This is line two of the legend for Y',
'yellow', 'none');
call legend('Sample LEGEND Window for Y',
'gray', 'blue');
return;
MAIN:
TERM:
return;
See Also
•
“ENDLEGEND” on page 343
•
“POPLEGEND” on page 595
•
“PUSHLEGEND” on page 603
•
“PUTLEGEND” on page 606
LENGTH (return string length)
Returns the length of a trimmed character string
Syntax
length=LENGTH(cval, <’NOTRIM’ >);
499
500
Chapter 13
•
SAS Component Language Dictionary
Required Arguments
length
the length of the trimmed character string.
Type
Numeric
cval
the character value whose length is to be determined.
Type
Character
Optional Argument
NOTRIM
specifies that trailing blanks should be counted as part of the string length.
Type
Character
Details
The resulting value is the position of the right-most nonblank character in the specified
string cval.
When NOTRIM is specified, LENGTH returns the length of a string, including trailing
blanks.
By default, variables automatically remove leading blanks when values are assigned to
them. The $CHAR format and informat must be assigned to a variable in order for
leading blanks to be considered in determining the length of a variable.
Examples
Example 1: Using the LENGTH Function
Return the length of the character variable S:
length s $ 5;
s=’ab ’;
l=length(s);
put ’L=’l;
This program produces the following output:
L=2
Example 2: Using the LENGTH Function with NOTRIM
Return the length of the character variable S, using the NOTRIM option:
s = ’xy ’;
l = length(s, ’notrim’);
put ’L=’l;
This program produces the following output:
L=4
LENGTH (declaration)
501
See Also
“MLENGTH” on page 544
LENGTH (declaration)
Declares variables and specifies their length and whether their data type is numeric or character
Category:
Note:
Declarative Statement
SAS Statement with limitations in SCL
Syntax
LENGTH<variable-list> <DEFAULT=n> ;
Optional Arguments
variable-list
is one or more variables, specified as variable-1 <. . . variable-n> <$> length, where
variable
names a variable to be assigned a length.
$
designates that the preceding variable or variables are character type.
length
is the length of the preceding variable or variables. Length can range from 1 to
32,767 for character variables. All numeric variables have a length of 8. If you
specify a different length for a numeric variable, SCL still reserves 8 bytes for it.
Type: Character
DEFAULT=n
is the maximum length of character variables that are not defined by a LENGTH
statement. If this option is not used, the default length for character variables is 200.
Type: Numeric
Details
In SCL, LENGTH is a declarative statement and can be used only to set the lengths of
nonwindow variables. If you attempt to specify a length for a window variable, a
compile error occurs.
You typically place LENGTH statements at the beginning of a program, before the first
labeled section. A compiler error occurs if you attempt to place a LENGTH statement
within a DO group or within a conditional clause.
You can use the LENGTH statement to reduce the amount of memory required for
storing character-type nonwindow variables. For example, if your program assigns only
single-character values to the variable CODE, and if the default length of character
variables is 200, then you can save 199 bytes of storage space by defining the length of
the variable explicitly in the SCL program. To do so, use a statement like the following:
length code $ 1;
For details about the LENGTH statement in the Base SAS language, see the “LENGTH
Statement” in SAS Statements: Reference.
502
Chapter 13
•
SAS Component Language Dictionary
Example
Set the maximum length of all character variables that are not defined by a LENGTH
statement to 150:
length default=150;
length a $ 8;
INIT:
b='';
max_a=mlength(a);
max_b=mlength(b);
put max_a= max_b=;
return;
The output is:
max_a=8 max_b=150
See Also
“DECLARE” on page 304
LETTER
Displays the FSLETTER window or sends a letter that was created with the FSLETTER procedure
Category:
Utility
Syntax
CALL LETTER(letter-entry<,open-mode<,table-name> > );
Required Argument
letter-entry
is a catalog containing one or more LETTER, FORM, or EDPARMS entries. A oneor two-level name is assumed to be catalog or libref.catalog. The catalog is created
if it does not already exist.
Type: Character
Optional Arguments
open-mode
specifies the type of access to the FSLETTER window:
'BROWSE'
opens the catalog or letter-entry for browsing.
'EDIT'
opens the catalog or letter-entry for editing. (This is the default.)
'PRINT'
prints a letter for each row in the SAS table specified by table-name. The SEND
window is not displayed for the items that are printed. PRINT mode is valid only
when the specified entry is a letter.
LETTER
503
'SEND'
displays the FSLETTER SEND window for one row (or letter), enabling a user
to customize the letter. To use this option, you do not have to specify a value for
table-name. If a table name is provided, the letter is displayed in the SEND
window with the fields filled with values from the first row in the table. This
mode is valid only when the specified entry is a letter.
Type: Character
table-name
is the SAS table containing values for the fill-in fields. Use the syntax
<libref.>member-name<(SAS-data-set-options)>. If you omit libref, the default SAS
data library, WORK, is used.
Specify '' to use the _LAST_ table. If no _LAST_ table exists, the program halts.
You can add a list of SAS data set options following the table name. The list must be
enclosed in parentheses. Valid data set options include DROP, KEEP, RENAME,
WHERE, and CNTLLEV. See SAS Data Set Options: Reference for a list of data set
options and their descriptions.
Type: Character
Details
The LETTER routine displays the FSLETTER window or sends a letter.
Note: The FSLETTER window is not displayed if a PRINT argument is used.
If the value supplied for letter-entry is a three- or four-level name, the user is returned to
the calling application when the FSLETTER window is closed. If a one- or two-level
name is supplied, the user is returned directly to the calling application when the SAS
Explorer window is closed.
SAS data set options can be specified by enclosing them within parentheses immediately
following the table-name argument, as in the following example:
call letter('my.letters.subscrib','print',
'personal(where=(name="John"))');
In order to use the LETTER routine, SAS/FSP Software must be installed. For more
information about the commands that are available in the FSLETTER procedure, see the
SAS/FSP Procedures Guide.
Example:
•
Open the FSLETTER window to edit a document named SUBSCRIB:
call letter('my.letters.subscrib');
•
Send a copy of the SUBSCRIB letter for each row in the SAS table
SUBSCRIB.DATA. Direct FSLETTER output to a print file when you use CALL
LETTER.
rc=filename ('myfile',fname);
call execcmdi('prtfile myfile');
call letter('my.letters.subscrib','print','subscrib.data');
•
Send a copy of the SUBSCRIB letter for the first row in the SAS table
SUBSCRIB.DATA:
call letter('my.letters.subscrib','send','subscrib.data');
SEND mode for the letter SUBSCRIB accepts user input.
504
Chapter 13
•
SAS Component Language Dictionary
See Also
“FSEDIT” on page 414
LIBLIST
Displays a host selection window that lists the currently assigned librefs, and returns user's selections
Category:
SAS Table
Syntax
selections=LIBLIST(<sel-excl<,engine<,message <,autoclose<,num-sel> > > > > );
Required Argument
selections
contains one or more librefs from the list, or blank if no selection is made. Multiple
selections are separated by blanks. By default, selections is 200 bytes long. To
accommodate values longer than 200 bytes, explicitly declare selections with a
longer length.
Type: Character
Optional Arguments
sel-excl
is one or more librefs to include or exclude from the selection list window. Specify
names using a style described in “Styles of Name Specification” on page 505.
Type: Character
engine
is one or more engines to use as criteria for determining which librefs are displayed.
Specify names using a style described in “Styles of Name Specification” on page
505.
Type: Character
message
is the text for a message to display above the selection list. The default message tells
users to make up to the number of selections in num-sel.
Type: Character
autoclose
is an obsolete argument but is retained for compatibility with earlier releases. If you
want to specify a value for num-sel, then specify ' ' as a placeholder for this
argument.
Type: Character
num-sel
specifies the maximum number of items a user can select from the list. To display
the list for information purposes only (no selections allowed), specify 0. To specify
unlimited selections, use a value such as 9999 that is larger than the number of
available selections. A user cannot make a number of selections that exceeds the
number of items in the list.
LIBLIST 505
Type: Numeric
Details
Styles of Name Specification
To specify more than one name, separate the names with a space — for example,
MYLIB1 MYLIB2.
To specify all names, use an asterisk ('*') or a null string ('').
To specify all names except those listed after the NOT sign, use a NOT sign (¬ or ^)
followed by one or more names. For example, ^MYLIB1 displays all defined librefs
except MYLIB1.
Usage
LIBLIST opens the Library Selector window, which lists librefs, engines, and the
physical names of the operating system files. However, only the selected libref is
returned. The window contains a Browse button which a user can select to display the
SAS Explorer window and select from the librefs that are currently assigned and their
contents. After browsing data libraries, a user can select File ð Close to return to the
Library Selector window.
If you omit all the arguments for LIBLIST (for example, selections=liblist();),
the selection list window lists all librefs that have been assigned in the current SAS
session.
You can provide a default value that will be initially selected when the libref selection
list is displayed. To do this, assign the value to the selections variable before calling
LIBLIST.
If a user closes the selection list window without making a selection, LIBLIST returns a
blank value unless there was an initial value for selections before LIBLIST was called.
Selections from the window can be returned in the current result list, if one is available.
The current result list is a special SCL list that is automatically filled with the values that
are selected from a selection list. To use a current result list, use the MAKELIST
function to create the list, and use the CURLIST function to designate it as the current
result list. The current result list must exist before you call the LIBLIST function.
When LIBLIST is invoked, the current result list is cleared. After LIBLIST is invoked,
the result list contains the following named items:
TAG
identifies the list as one that was created by the LIBLIST function.
Type: Character
COUNT
contains the number of selected librefs, or 0 if a user makes no selections or issues a
CANCEL command in the list window.
Type: Numeric
LIBREF
contains the name of each selected libref. There is one LIBREF element for each
selected libref name.
Type: Character
LIBNAME
contains the physical name of the operating system file for each selected libref.
There is one LIBNAME element for each selected libref.
506
Chapter 13
•
SAS Component Language Dictionary
Type: Character
Example: Ways to Use LIBLIST
•
Create a selection list that displays all librefs except MYLIB1 and MYLIB2, and
display the message 'Choose a libref'.
select=liblist('^mylib mylib2','*',Choose a libref');
•
Create a selection list that displays all librefs associated with the V609 engine, and
exclude the librefs SASHELP and MAPS. Allow users to make up to three
selections.
select=liblist('^sashelp maps','v609',
'Choose up to 3 librefs','',3);
•
Create a current result list to receive user selections. Use MAKELIST to create the
list and CURLIST to define it as the current result list. Display all librefs except
MYLIB1 and MYLIB2, and allow users to make up to five selections. Use a DO
loop to retrieve the selections from the current result list.
listid=makelist();
rc=curlist(listid);
select=liblist('^ mylib1 mylib2',' ',
'Choose up to 5 librefs','', 5);
n=getnitemn(listid,'COUNT');
do i=1 to n;
libref=getnitemc(listid,'LIBREF',i);
physname=getnitemc(listid,'LIBNAME',i);
put libref= physname=;
end;
See Also
•
“CATLIST” on page 240
•
“DIRLIST” on page 323
•
“FILELIST” on page 381
LIBNAME
Assigns or deassigns a libref for a SAS data library
Category:
SAS Table
Syntax
sysrc=LIBNAME(libref<,SAS-data-library<,engine <,options> > > );
Required Arguments
sysrc
contains the return code for the operation:
0
The operation was successful.
LIBNAME
>0
The operation was not successful.
<0
The operation was completed, but a warning or a note was generated.
507
Type: Numeric
libref
is the libref to assign.
Type: Character
Optional Arguments
SAS-data-library
is the physical name of the SAS data library to be associated with the libref. This
name can be up to 32K characters long. Specify this name as required by the host
operating system.
Type: Character
engine
is the engine to use for accessing the SAS files in the data library. If you are
specifying a SAS/SHARE server, the engine should be REMOTE.
Type: Character
options
are options that are used by the specified engine. Multiple options are delimited by
blank spaces in the same quoted string. For information about engines and options,
see the SAS documentation for your operating environment.
Type: Character
Details
The LIBNAME function follows the rules for the LIBNAME statement in Base SAS
software.
Operating Environment Information
Some operating systems allow a SAS-data-library value of ' ' (with a space) and
some allow '.' to assign a libref to the current directory. The behavior of
LIBNAME when a single space or a period is specified for SAS-data-library is host
dependent. Under some operating systems, librefs can be assigned using system
commands outside the SAS session.
Examples
Example 1: Assigning a Libref
Assign the libref NEW to SAS-data-library. If an error or warning occurs, display the
message on the message line.
if (libname('new','SAS-data-library')) then
_msg_=sysmsg();
Example 2: Using Multiple Options When Assigning a Libref
Assign the libref MYLIB to SAS-data-library, and the server name and user access
rights.
rc=libname('mylib','SAS-data-library','remote',
508
Chapter 13
•
SAS Component Language Dictionary
'server=servername access=readonly');
Example 3: Deassigning a Libref
Deassign the libref NEW. If an error or warning occurs, display the message on the
message line.
if (libname('new')) then
_msg_=sysmsg();
Example 4: Using a List to Assign a Libref to Multiple SAS Data
Libraries
Assign the libref DEF to several PC files whose names are stored in an SCL list:
lid=makelist();
rc=insertc(lid,”(“,-1);
rc=insertc(lid,”'M:\SAS\MAPS'”,-1);
rc=insertc(lid,”'C:\CATALOGS\sasuser'”,-1);
rc=insertc(lid,”)”,-1);
rc=libname('DEF',' ','','',lid);
Assign the libref DEF to several UNIX files whose names are stored in an SCL list:
v1=”(/mylib/store/data/facilities'”;
v2=”'/mylib/store/data/hresorces'”;
v3=”'/mylib/store/data/supplies')”;
lid = makelist ();
rc =insertc(lid,v1,-1);
rc =insertc(lid,v2,-1);
rc =insertc(lid,v3,-1);
RC =LIBNAME('DEF',' ',”,”,lid);
See Also
“LIBREF” on page 508
LIBREF
Verifies that a libref has been assigned
Category:
SAS Table and Utility
Syntax
sysrc=LIBREF(libref);
Required Arguments
sysrc
contains the return code for the operation:
=0
The operation was successful.
<0
The operation was completed, but a warning or a note was generated.
>0
The operation was not successful.
Type: Numeric
LISTC and LISTN
509
libref
is the libref to be verified.
Type: Character
Example
Verify a libref. If an error or warning occurs, the message is displayed on the application
window's message line.
if (libref('sashelp'))
then _msg_=sysmsg();
See Also
“LIBNAME” on page 506
LISTC and LISTN
Display a selection list window containing values stored in a catalog entry
Category:
Selection List
Syntax
selections=LISTC(entry<,message<,autoclose<,num-sel> > > );
selections=LISTN(entry<,message<,autoclose<,num-sel> > > );
Required Arguments
selections
contains one or more character values that have been selected by the user.
For LISTC, if a selection is not made, selections will be blank. Multiple selections
are separated by blanks. By default, selections is 200 bytes long. To accommodate
values longer than 200 bytes, explicitly declare selections with a longer length.
For LISTN, selections is the first value that the user selected. The value is numeric.
Type: Character or Numeric
entry
is a LIST entry (for LISTN) or a HELP, LIST, or MENU entry (for LISTC). The
entry must be specified as entry.type for an entry in the current catalog or as
libref.catalog.entry.type for an entry in a different catalog.
Type: Character
Optional Arguments
message
is text for a message to be displayed above the selection list. The default message
tells users to make up to the number of selections specified by num-sel, or 1 if numsel is not provided. The default is 1.
Type: Character
510
Chapter 13
•
SAS Component Language Dictionary
autoclose
specifies whether the selection list window closes automatically after a user makes a
selection when only one choice is allowed:
'Y'
closes the window automatically. (This is the default.)
'N'
leaves the window open until the user explicitly closes it.
This option is ignored when num-sel is not 1. However, use '' as a placeholder if
you are also specifying a value for num-sel.
Type: Character
num-sel
specifies the maximum number of items a user can select from the list. To display
the list for information purposes only (no selections allowed), specify 0. To specify
an unlimited number of selections, use a value such as 9999 that is larger than the
number of available selections. The default is one selection.
Type: Numeric
Details
LISTC automatically displays a selection list containing character values that are stored
in a LIST, HELP, or MENU entry. A LIST entry that is used with LISTC must be of
character type. Typically, a LIST entry is used if the selections in the LIST entry are
self-explanatory. A HELP or MENU entry is used if a definition is needed next to the
selection.
LISTN automatically displays a selection list containing numeric values stored in a LIST
entry, which must be of numeric type. The numeric values are displayed using the
format that was specified for the LIST entry. If no format was specified, the values are
displayed using the BEST. format.
For a selection list that is produced with a LIST entry, you can provide a default or
initial selected value by specifying a value for selections before calling LISTC. If
selections contains valid values when LISTC is invoked, those values are automatically
designated as selected when the selection list is displayed.
When multiple selections are allowed in LISTN, selections contains the first value
selected from the list. However, the values for all selections can be returned in the
current result list, if one is available. The current result list is a special SCL list that is
automatically filled with the values selected from a selection list. To use a current result
list, use the MAKELIST function to create the list, and use the CURLIST function to
designate it as the current result list. The current result list must exist before you call
LISTC. You can use GETITEMC to retrieve values from the list.
Examples
Example 1: Using LISTC with a LIST Entry
Open the entry MYLIST.LIST in the current catalog, and then display it as a selection
list. Users can make up to four selections. The selected values are retrieved from the
current environment list.
listid=makelist();
rc=curlist(listid);
selections=listc('mylist.list','','n',4);
n=listlen(listid);
do i=1 to n;
LISTC and LISTN
511
item=getitemc(listid,i);
put item=;
end;
Example 2: Using LISTC with the Current Result List
Create LIST_C and make it the current list. Use LISTC to display a selection list
containing the values ABC, DEF, GHI, and JLK, which are stored in MYCHAR.LIST,
and allow a user to make up to 4 selections.
list_c=makelist();
cur_list=curlist(list_c);
/* Display the list and put the user
*/
/* selection in SELECTIONS.
*/
/* Then print the number of selections. */
selections=listc('mychar.list',' ',' ',4);
put 'User selected' selections;
/* Find out the number of items
*/
/* in LIST_C and print the number.
*/
num_selected=listlen(list_c);
put 'Total number selected is' num_selected;
/* Get the selections from
*/
/* the current list
*/
/* and print each one.
*/
do i=1 to num_selected;
item=getitemc(list_c,i);
put 'Item' i 'is ' item;
end;
Testing the program and selecting GHI, DEF, JKL, and then ABC produces the
following output:
User selected GHI DEF JKL ABC
Total number selected is 4
Item 1 is GHI
Item 2 is DEF
Item 3 is JKL
Item 4 is ABC
Example 3: Using LISTN with the Current Result List
Create LIST_N and make it the current list. Use LISTN to display a selection list
containing the numbers 1, 2, 3, and 4, which are stored in MYLIST.LIST, and allow a
user to make up to 4 selections.
list_n=makelist();
cur_list=curlist(list_n);
/* Display the list and put the first user
*/
/* selection in SELECTED_FIRST,
*/
/* then print the number of user selections. */
selected_first=listn('mylist.list',' ',' ',4);
put 'First selection is ' selected_first;
/* Find out the number of items in LIST-N */
/* and print the number.
*/
num_selected=listlen(list_n);
put 'Total number selected is ' num_selected;
/* Get any other selections from
*/
/* the current list
*/
/* and print each number.
*/
512
Chapter 13
•
SAS Component Language Dictionary
do i=1 to num_selected;
item=getitemn(list_n,i);
put 'Item ' i 'is ' item;
end;
Testing the program and selecting 3, 2, 4, and 1, produces the following output:
First selection is 3
Total number selected is 4
Item 1 is 3
Item 2 is 2
Item 3 is 4
Item 4 is 1
See Also
“DATALISTC and DATALISTN” on page 299
LISTLEN
Reports the length of an SCL list
Category:
List
Syntax
n=LISTLEN(list-id );
Required Arguments
n
contains either the length of an SCL list or status information:
>0
the length of a non-empty list
0
the list is empty
−1
the list identifier is invalid.
Type: Numeric
list-id
is the identifier of the list whose length is being queried, or any other number.
Type: Numeric or List
Details
The length of a list is the number of items in the list, excluding the contents of sublists.
Because LISTLEN returns -1 if list-id is an invalid list identifier, you can use LISTLEN
to determine whether a list exists. For example:
listid=getniteml(envlist('G'),'MYLIST');
invalid=(listlen(listid)=-1);
if invalid then
do;
put 'MYLIST in the global environment has been deleted.';
stop;
LNAMECHK
513
end;
Example
Create the empty list LISTA, and then insert LISTA into a copy of itself, LISTB. The
lengths of the two lists are then computed and are stored in the variables LEN_A and
LEN_B.
lista=makelist();
listb=copylist(lista);
listb=insertl(listb,lista);
len_a=listlen(lista);
len_b=listlen(listb);
_msg_='The length of LISTA is '||len_a||' and '||
'the length of LISTB is '||len_b;
This example shows that the length of LISTA is 0, whereas the length of LISTB is 1.
See Also
•
“MAKELIST” on page 527
•
“MAKENLIST” on page 528
LNAMECHK
Validates a path string
Category:
Image
Syntax
rc= LNAMECHK(path-string);
Required Arguments
rc
the return code for the operation:
0
The path string is a valid path to a file.
>0
The path string is not a valid path to a file.
Type
Numeric
path-string
the string generated by LNAMEMK.
Type
Character
Details
LNAMECHK validates that the specified path string refers to an external file that exists.
It does not determine whether the file contains a readable image.
514
Chapter 13
•
SAS Component Language Dictionary
Example
Test whether a file exists:
imgpath=lnamemk(2,fromdir,file)
rc=lnamechk(2,imgpath);
if (rc ne 0) then
do;
_msg_="File does not exist.";
end;
LNAMEGET
Decodes a path string
Category:
Image
Syntax
rc=LNAMEGET(path-string,type,<name-string1<,name-string2> <,options> > );
Required Arguments
rc
contains the return code for the operation:
0
successful
>0
not successful
Type: Numeric
path-string
is the string generated by LNAMEMK.
Type: Character
type
is the type of the path. See “LNAMEMK” on page 515 for more information. If no
other arguments are specified, the function returns only the type.
Type: Numeric
Optional Arguments
name-string
is the name-string provided in LNAMEMK. Specify enough name-string arguments
for the type. See “LNAMEMK” on page 515 for more information.
Type: Character
options
are any options used with LNAMEMK.
Type: Character
LNAMEMK
515
Details
Path strings that are created by LNAMEMK are not readable, and their internal format
may change from release to release. The only way to decode a path string is to use
LNAMEGET.
You may find it useful to encode an image filename with LNAMEMK and to store that
path string in a SAS data set. Then, later retrieve the path string and use LNAMEGET to
find the arguments that were originally specified in LNAMEMK.
If you use the type, name-string, and options arguments, they are filled with the
corresponding arguments specified in LNAMEMK (such as the libref/member name,
physical pathname, and so on). The number of optional arguments that you specify must
match the number specified in LNAMEMK.
Example:
•
Encode and decode a pathname. Store the type of path in TYPE, and store the
pathname in IMGFILE.
imgpath=lnamemk(1,filename);
rc=lnameget(imgpath,type,imgfile);
•
Encode and decode the location of an image file. Store the directory that contains the
image file in DIR, and store the filename in IMGFILE.
imgpath=lnamemk(2,dirname,filename);
rc=lnameget(imgpath,type,dir,imgfile);
See Also
•
“LNAMECHK” on page 513
•
“LNAMEMK” on page 515
LNAMEMK
Makes a path string for an image file
Category:
Image
Syntax
path-string=LNAMEMK(type,<name-string1<,name-string2> <,attributes> > );
Required Arguments
path-string
contains a packed string containing information about the file path and format.
Declare a length of at least 300 characters.
Type: Character
type
is a number from 1 through 5 that specifies the type of path used to read the external
file.
Type: Numeric
516
Chapter 13
•
SAS Component Language Dictionary
Optional Arguments
name-string
is the string that identifies the location of the image. The specification depends on
the value specified for type.
For type
use name-string1
1
physical-pathname
2
directory-pathname
3
fileref
4
fileref
5
libref.catalog.member
and name-string2
filename
filename
Type: Character
attributes
specify file-specific attributes. See File Types on page 835 and Attributes for
Reading Image Files on page 837 for possible choices. The FORMAT= attribute
must be specified for Targa images, for images residing in SAS catalogs, and for
host-specific formats. FORMAT is not required in other cases, but it is always more
efficient to specify it.
Type: Character
Details
LNAMEMK creates a character variable that contains information about the location of
the image as well as other image attributes.
The path string can be used with the READ and WRITE commands in IMGOP or with
the image object. The path string contains binary data and can be decoded only with the
LNAMEGET and LNAMECHK functions.
Example
Create path strings for image files:
length file $ 200;
file=lnamemk(1,filename,'format=gif');
file=lnamemk(2,directory,filename,'format=gif');
file=lnamemk(3,fileref,'format=gif');
file=lnamemk(4,fileref,filename,'format=gif');
imgentry=libref||"."||catalog||"."||member;
file=lnamemk(5,imgentry,'format=cat');
See Also
•
“IMGOP” on page 460
•
“LNAMECHK” on page 513
•
“LNAMEGET” on page 514
LOADCLASS
517
LOADCLASS
Loads a class and returns its identifier number
Syntax
class-id=LOADCLASS(class-name);
Required Arguments
class-id
contains the identifier that has been assigned to the class. If the class is not loaded,
class-id contains 0.
Type
Numeric
class-name
is the one- to four-level name of the CLASS catalog entry to load. If class-name is a
one- or two-level name, then the current search path is used to find the CLASS entry.
If the CLASS entry was previously loaded, then the same class identifier is returned.
Otherwise, the CLASS entry is loaded from the catalog into the application class list,
and the class identifier is returned in class-id.
Type
Character
Details
LOADCLASS loads a class definition from a CLASS catalog entry. The identifier
number that LOADCLASS returns can be used to create an instance of the class with the
INSTANCE function.
Example
Load SASUSER.CLASSES.TIMER.CLASS and use the INSTANCE function to create
an instance of the TIMER class:
timerclass=loadclass(’sasuser.classes.timer’);
timer=instance(timerclass);
See Also
•
“APPLY” on page 219
•
“INSTANCE” on page 474
•
“LOADRES” on page 518
•
“_NEO_” on page 557
•
“NOTIFY” on page 569
•
“SEND” on page 649
•
“SUPAPPLY” on page 686
•
“SUPER” on page 688
518
Chapter 13
•
SAS Component Language Dictionary
LOADRES
Loads a RESOURCE entry
Category:
Object Oriented
Syntax
resource-id=LOADRES(resource-name);
Required Arguments
resource-id
contains the identifier that is assigned to the resource list.
Type: Numeric
resource-name
is the RESOURCE catalog entry to load. If resource-name is a one- or two-level
name, the current search path is used to find the RESOURCE entry.
Type: Character
Details
LOADRES loads a list of classes from a RESOURCE entry. This list is called a resource
list. RESOURCE entries are used primarily by FRAME entries, although you can create
RESOURCE entries for component classes as well. This function is useful for loading
several classes or even entire class hierarchies at one time instead of having to load
several CLASS entries.
If a class contained in the resource list has already been loaded, the existing class
replaces the class in the resource list (although the RESOURCE entry is not modified).
This prevents duplicate class lists for the same class name.
Example
Load a resource list that is stored in APPQR.HIER1.GROUPS.RESOURCE, then load
several classes contained in the RESOURCE entry. After the LOADRES call, the
LOADCLASS calls do not have to read the classes from the catalog.
groups = loadres('appqr.hier1.groups.resource');
c1=loadclass('appqr.hier1.c1.class');
c2=loadclass('appqr.hier1.c2.class');
c3=loadclass('appqr.hier1.c3.class');
See Also
•
“APPLY” on page 219
•
“INSTANCE” on page 474
•
“LOADCLASS” on page 517
•
“_NEO_” on page 557
•
“NOTIFY” on page 569
LOCATEC and LOCATEN
•
“SEND” on page 649
•
“SUPAPPLY” on page 686
•
“SUPER” on page 688
519
LOCATEC and LOCATEN
Search a SAS table for a row that contains a specified value
Category:
SAS Table
Syntax
rc=LOCATEC(table-id,col-num,cval<,sort<,direction> > );
rc=LOCATEN(table-id, col-num,nval <,sort<,direction> > );
Required Arguments
rc
contains information about the search:
>0
the number of rows read before a match is found
0
no row with a matching value was found
Type: Numeric
table-id
is the identifier that was assigned when the SAS table was opened. If table-id is
invalid, the program halts.
Type: Numeric
col-num
is the number of the column to search for. This number can be returned by the
VARNUM function. If the number is invalid, the program halts and sends a message
to the log.
Type: Numeric
cval
is the character value for LOCATEC to search for. If cval is not a character value,
the program halts and sends a message to the log.
Type: Character
nval
is the numeric value for LOCATEN to search for. If nval is not a numeric value, the
program halts and sends a message to the log.
Type: Numeric
Optional Arguments
sort
indicates whether the SAS table is sorted:
'A'
The table is sorted in ascending order.
520
Chapter 13
•
SAS Component Language Dictionary
'D'
The table is sorted in descending order.
'U'
The table is not sorted. (This is the default.)
Type: Character
direction
specifies the direction in which to search the SAS table:
'A'
searches all rows, starting with the first row. (This is the default unless the
table is opened in 'IS' mode.)
'B'
searches from the previous row backward.
'F'
searches from the next row forward. (This is the default if the table is
opened in 'IS' mode.)
Type: Character
Details
LOCATEC and LOCATEN do not search for partial values. For LOCATEC, preceding
blanks are part of cval but trailing blanks are not. Therefore, you can facilitate searching
for LOCATEC by using the LEFT function to left-justify character values.
LOCATEC and LOCATEN search all rows, starting with the first row by default and
skipping rows marked for deletion. When a WHERE clause is active, these functions
search the rows that meet the WHERE condition for a match. If a matching row is found,
it is loaded into the Table Data Vector (TDV). Otherwise, the current row remains in the
TDV.
LOCATEC and LOCATEN return the number of rows read before a match is found.
This number may not correspond to the row number where the match is found because
these functions skip deleted rows. Moreover, if a WHERE clause is active, they read
only the that meet the WHERE condition, and they may include appended rows that
meet the WHERE condition. Also, if direction is supplied, the number returned is the
number of rows read from the previous row where the search began. By default, the
search direction is forward, starting with the first row in the table.
If the table is sorted, then specifying 'A' or 'D' for sort uses the more efficient binary
search algorithm. Perform a binary search only when you have member-level access so
that no one else can be editing the table concurrently. With a binary search, LOCATEC
and LOCATEN make assumptions about how the data is sorted, and they assume that
they can identify the first and last rows. If the table is being edited concurrently, rows
could be appended so that the table is no longer in sorted order. As a result, the binary
search might not find the correct values.
Examples
Example 1: Using the LOCATEC Function
Locate a customer named SMITH in the PAYROLL table. The table is opened with a
table-id of TABLEID and is sorted by NAME. The customer's name is specified in the
CUSTOMER column.
customer='SMITH';
rc=locatec(tableid,varnum(tableid,'name'),customer,'a');
if (rc=0) then _msg_=
'There is no customer named '||customer||'.';
LOCK 521
else do;
...more SCL statements...
end;
return;
Example 2: Using the LOCATEN Function
Locate a house whose price is $94,000 in the SASUSER.HOUSES table, which is
opened with a table-id of HOUSEID. The price is specified in the window variable
PRICE.
houseid=open('sasuser.houses');
price=94000;
rc=locaten(houseid,varnum(houseid,'price'),price);
if (rc=0) then
_msg_='No house is priced at '||
putn(price,'dollar9.2')||'.';
else do;
rows=curobs(houseid);
_msg_=
'The specified price was found in row '||rows;
end;
return;
See Also
•
“FETCH” on page 368
•
“FETCHOBS” on page 369
•
“GETVARC and GETVARN” on page 433
•
“SET” on page 651
LOCK
Locks or unlocks a SAS table or a SAS catalog entry
Category:
SAS Table
Syntax
sysrc=LOCK(member<,action> );
Required Arguments
sysrc
contains the return code for the operation:
0
successful
>0
not successful
<0
the operation was completed, but a warning or a note was generated.
522
Chapter 13
•
SAS Component Language Dictionary
member
is a member of a SAS data library or a SAS catalog entry. The value that you specify
can be a one-, two-, three-, or four-level name. A one-level name is presumed to be a
libref, whereas a two-level name defaults to the SAS table type DATA.
Type: Character
Optional Argument
action
specifies an action to be performed on the SAS table or catalog entry:
'CLEAR'
unlocks the specified SAS table(s) or SAS catalog entry.
'LOCK'
locks the specified SAS table(s) or SAS catalog entry. (This is the default.)
'QUERY'
queries the lock status of a SAS table or a SAS catalog entry.
_SWNOLKH
not currently locked. SYSRC of -630099.
_SWLKUSR
locked by another user. SYSRC of -630097.
_SWLKYOU
locked or in use by the caller. SYSRC of -630098.
Type: Character
Details
If action is not provided, the action defaults to LOCK.
Example
Lock the data library that is associated with a libref of A, unlock data view LIB.A, and
lock LIB.A.B.PROGRAM. Then, query the lock state of the FOO.ONE table:
rc=lock('a');
rc=lock('lib.a.view','clear');
rc=lock('lib.a.b.program');
rc=lock('foo.one.data','query');
if (rc=%sysrc(_SWLKUSR)) then
_msg_='Table foo.one is currently locked.';
LOOKUPC
Searches for a string among a list of valid tokens
Category:
Command
Syntax
rc=LOOKUPC(string,token-1<, . . .,token-12> );
LOOKUPC
523
Required Arguments
rc
contains the return code for the operation:
0
indicates that no match was found.
>0
is the position in the token list if a unique match was found.
<0
is the negative of the position in the token list if a duplicate token was
found.
Type: Numeric
string
is the character value to search for.
Type: Character
token
is up to 12 character values, separated by commas.
Type: Character
Details
A token can be a name, a literal, digits, or special characters. This function is useful for
looking up valid commands.
The function accepts abbreviations as valid commands. That is, the function reports a
match if the search string matches the starting characters of a token.
LOOKUPC does not search the token list for embedded strings. For example, the search
string LIST would not be found in the token NEWLIST.
Example
Get the command (SURVEY, NEWLIST, or ADDNAME) that the user issued from the
command line, and execute code accordingly:
array cmds{*} $8 ('SURVEY','NEWLIST','ADDNAME');
INIT:
control always;
return;
MAIN:
cmdword=WORD(1,'u');
cmdnum=lookupc(cmdword,cmds{1},cmds{2},cmds{3});
select;
when (cmdnum=1)
...SCL statements to process SURVEY command...
when (cmdnum=2)
...SCL statements to process NEWLIST command...
when (cmdnum=3)
...SCL statements to process ADDNAME command...
otherwise _msg_='Command conflict';
end;
In this example, SUR, NEWL, and ADDN are considered valid commands.
524
Chapter 13
•
SAS Component Language Dictionary
LVARLEVEL
Fills an SCL list with the unique values of a column from a SAS table
Category:
List
Syntax
rc=LVARLEVEL(dsid,varname,n-level<,list-id> );
Required Arguments
rc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
dsid
is the identifier that was assigned when the table was opened. An invalid dsid
produces an error condition.
Type: Numeric
varname
is the column whose unique formatted values are to be reported.
Type: Character
n-level
is the name of the variable in which the function stores the number of unique values
(or levels). This variable must be initialized to a nonmissing value before its value is
set by the LVARLEVEL function.
Type: Numeric
Note
This parameter is an update parameter. See “Input, Output, and Update
Parameters” on page 38 for more information.
Optional Argument
list-id
is the identifier of the list to fill with the unique formatted values. If list-id is not
provided, the values are placed in the current result list. An invalid list-id produces
an error condition.
Type: Numeric or List
Details
The values are placed in the list identified by list-id, or in the current result list identified
by CURLIST (if list-id is not specified). The values placed in the list are always
character values. It is an error if list-id is omitted and you have not created a current
result list with the CURLIST function. n-level must be a column, because LVARLEVEL
MAKEARRAY 525
uses it to store the number of unique values it finds. n-level must be initialized to any
value except missing before LVARLEVEL executes.
Examples
Example 1: Placing Values in the Current List
Get the unique formatted values for the table column NAME from SASUSER.CLASS,
place the values in the current list, and print them:
dsid=open('sasuser.class');
nlevels=0;
rc=curlist(makelist());
rc=lvarlevel(dsid,'name',nlevels);
put nlevels=;
call putlist(curlist(),'levels',0);
rc=close(dsid);
Example 2: Placing Values in a Specified List
Get the unique formatted values for the table column NAME from SASUSER.CLASS,
place the values in the specified list, and print them:
dsid=open('sasuser.class');
nlevels=0;
listid=makelist();
rc=lvarlevel(dsid,'name',nlevels,listid);
put nlevels=;
call putlist(listid,'levels',0);
rc=close(dsid);
rc=dellist(listid);
See Also
•
“CURLIST” on page 293
•
“OPEN” on page 574
•
“VARLEVEL” on page 716
•
“VARSTAT” on page 722
MAKEARRAY
Creates an array of the given size with all elements in the array initialized to missing for numeric values or
blank for character values
Category:
Array
Syntax
array=MAKEARRAY(dim1<,...,dimN> );
526
Chapter 13
•
SAS Component Language Dictionary
Required Arguments
array
is the dynamic array to be created. A non-dynamic array causes an error condition.
Type: Array
dim1,...,dimN
is the size of each specified dimension. If you specify negative sizes or an invalid
number of dimensions, an error condition occurs.
Type: Numeric
Details
Unlike static arrays, whose bounds must be set at compile time, you can create and
resize (change the bounds of) dynamic arrays at run time. The low bound of the dynamic
array will always be 1, and the high bound will be determined as given at run time. If
you create a one-dimensional dynamic array with 5 elements, then the low bound and
high bound will be 1 and 5, respectively. The array must be declared using an asterisk
(*) for the array dimensions with no array elements or initial values specified. The
syntax is the same as for a reference array. For example, the following lines declare a
one-dimensional numeric dynamic array named A and a two-dimensional character
dynamic array named B:
DCL num A(*);
DCL char B(*,*);
The MAKEARRAY function creates an array of the given size. All elements in the array
initialized to missing for numeric values or blank for character values. The number of
dimensions must be the same as what was specified in the DECLARE statement.
If you use the MAKEARRAY function to resize a dynamic array, all the data is lost and
becomes garbage. If you try to reference an array element without first creating the
array, an error occurs.
Dynamic arrays can be used with the other existing array functions (DIM, HBOUND,
LBOUND) as long as the array has been created with MAKEARRAY. If you try to use
these other functions without first creating the array, a program halt occurs.
Examples
Example 1: Create a One–Dimensional Array
This example creates a one-dimensional array of 5 elements.
DCL num a(*);
a = makearray(5);
Example 2: Create a Two–Dimensional Array
This example creates a two-dimensional 5x5 array.
DCL num a(*,*);
a = makearray(5,5);
Example 3: Create an Array from a Table
This example uses table work.a, which has only numerical variables. The data from all
the table rows is placed into a two-dimensional array. The dimensions and size of the
array are determined by the number of rows and columns in the table.
MAKELIST
init:
/* Open the table and create the array. */
DCL num arr(*,*) rc;
dsid = open('work.a');
nlobs = attrn(dsid, 'NLOBS');
nvars = attrn(dsid, 'NVARS');
arr = makearray(nlobs,nvars);
/* Move the contents of the table into the array. */
do i = 1 to dim(arr, 1);
rc = fetch(dsid);
do j = 1 to dim(arr, 2);
arr[i,j] = getvarn(dsid, j);
end;
end;
/* Close the table and delete the array. */
call close(dsid);
rc = delarray(arr);
return;
See Also
•
“DECLARE” on page 304
•
“DELARRAY” on page 307
•
“REDIM” on page 610
•
“DIM Function” in SAS Functions and CALL Routines: Reference
•
“HBOUND Function” in SAS Functions and CALL Routines: Reference
•
“LBOUND Function” in SAS Functions and CALL Routines: Reference
•
“Introduction to SCL Arrays” on page 41
MAKELIST
Creates an SCL list
Category:
List
Syntax
list-id=MAKELIST(<n<, visibility> > );
Required Argument
list-id
contains the identifier of the new list, or 0 if the list could not be created.
Type: Numeric or List
Optional Arguments
n
is the number of items to place in the list initially. By default, n is 0.
Type: Numeric
527
528
Chapter 13
•
SAS Component Language Dictionary
visibility
specifies whether the list is global or local:
'G'
The list is global and can be shared by all applications executing in the
same SAS session. A global list is deleted when the SAS session ends.
'L'
The list is local to the current SAS application. A local list is deleted when
the application ends. (This is the default.)
Type: Character
Details
MAKELIST creates either an empty list or a list with the number of items specified in n.
Each item contains a missing value. Use the list identifier returned by MAKELIST with
all other SCL list functions that use the list.
SCL lists can contain numeric items, character items, other list items, or object items.
Each item can have a name. Both lists and list items have attributes. See “Introduction to
SCL Lists” on page 54 for complete information about using SCL lists.
Example
Create lists in the local and global environments:
n = 12;
/* Make an empty local list. */
list1=makelist();
/* Make a local list with 24 items.
list2=makelist(2*n);
/* Make an empty global list. */
list3=makelist(0,'G');
*/
See Also
•
“CLEARLIST” on page 262
•
“COPYLIST” on page 284
•
“DELLIST” on page 311
•
“LISTLEN” on page 512
•
“MAKENLIST” on page 528
•
“PUTLIST” on page 607
•
“SAVELIST” on page 633
MAKENLIST
Creates an SCL list that contains named items
Category:
List
Syntax
list-id=MAKENLIST(visibility,name-1<, . . . ,name-n> );
MAKENLIST 529
Required Arguments
list-id
contains the identifier of the new list, or 0 if the list could not be created.
Type: Numeric or List
visibility
specifies whether the list is global or local:
'G'
The list is global and can be shared by all applications executing in the
same SAS session. A global list is deleted when the SAS session ends.
'L'
The list is local to the current SAS application. A local list is deleted when
the application ends. (This is the default.)
Type: Character
name
is one or more list item names, separated by commas. Item names are converted to
uppercase, and trailing blanks are removed. Each name can be any SCL string. The
same name can be used more than once. The maximum length of an SCL list item
name is 255 characters.
Type: Character
Details
MAKENLIST creates a list that contains an item for each name that you specify. Each
item contains a missing value. Use the list identifier returned by MAKENLIST with all
remaining functions that manipulate the list. When you create a list of named items, you
can assign or access list values by their names as well as by their positions. However, it
is more efficient to access items by position rather than by name.
You can use MAKENLIST to create structures that group related information into one
list. For example, a row in a SAS table can be placed in a named list where each named
item corresponds to the table column of the same name.
Note that the visibility argument (L or G) is required and is the first argument, unlike the
MAKELIST function. Note also that this function does not use an n argument.
Using MAKENLIST is simpler than using MAKELIST and then naming each item
independently.
Example
The following statement creates a list of four named items:
mylist=makenlist('L','A','B','C');
It is equivalent to these four statements:
mylist=makelist(3,'L');
rc=nameitem(mylist,1,'A');
rc=nameitem(mylist,2,'B');
rc=nameitem(mylist,3,'C');
See Also
•
“LISTLEN” on page 512
•
“MAKELIST” on page 527
530
Chapter 13
•
SAS Component Language Dictionary
•
“NAMEDITEM” on page 551
•
“NAMEITEM” on page 555
MESSAGEBOX
Displays a message window. Specifies the message with a list.
Category:
Utility
Syntax
returnedText=MESSAGEBOX(textlist-id<,icon<,buttons <,caption<,default<,right> > > > > );
Required Arguments
returnedText
the name of the button that a user pressed in the message dialog window. This text
can be
ABORT, APPEND, CANCEL, IGNORE, OK, NO, REPLACE, RETRY, YES, or
YESTOALL. When a user presses Enter instead of selecting a button, either default
is returned (if specified) or the text of the first button in the message window is
returned.
Type: Character
textlist-id
the identifier for the SCL list that contains the lines of text to display in the message
window. Lines that are too long are wrapped.
Type: List
Optional Arguments
icon
specifies the icon to display in the message window:
'I'
Information or note icon (default)
'?'
Query icon
'!'
Warning icon
'S'
Error icon (stop sign/hand)
Type: Character
buttons
specifies the set of command buttons to display in the message window:
'O'
Ok (default)
'OC'
Ok, Cancel
'YN'
Yes, No
'YNC'
Yes, No, Cancel
'YYNC'
Yes, Yes to all, No, Cancel
MESSAGEBOXC 531
'ARI'
Abort, Retry, Ignore
'RAC'
Replace, Append, Cancel
'RC'
Retry, Cancel
Type: Character
caption
the title for the message window.
Type: Character
default
specifies the button that is activated when a user presses Enter in the message
window instead of selecting a button. Default is specified by a single character that
corresponds to one of the characters specified in buttons. If default is not supplied,
the default selection is the first button in the message window.
Type: Character
right
specifies whether the text in the message window is right- or left- justified:
'N'
Left justify the text. (default)
'Y'
Right justify the text.
Type: Character
Details
MESSAGEBOX calls a host message window. If the message window cannot open, or if
textlist-id is invalid, the program halts. On hosts that allow users to close the message
window without selecting a button, CANCEL is returned even if it is not one of the
button choices.
Example
The code below creates a window to prompt users to save their changes.
commandlist=makelist();
commandlist=insertc(commandlist,
'You have not saved the latest changes.',1);
commandlist=insertc(commandlist,
'Do you want to save your changes?',2);
command=messagebox(commandlist,'!','YN','Save?','Y','');
put command;
commandlist=dellist(commandlist);
See Also
“MESSAGEBOXC” on page 531
MESSAGEBOXC
Displays a message window. Specifies the message with a character string.
Category:
Utility
532
Chapter 13
•
SAS Component Language Dictionary
Syntax
returnedText=MESSAGEBOXC(text<,icon<,buttons <,caption<,default<,right> > > > > );
Required Arguments
returnedText
the name of the button that the user pressed in the message dialog window. This text
can be ABORT, APPEND, CANCEL, IGNORE, OK, NO, REPLACE, RETRY,
YES, or YESTOALL. When a user presses Enter instead of selecting a button,
either the default button name is returned (if specified) or the text of the first button
in the message window is returned.
Type: Character
text
the text to display in the message window. Lines that are too long are wrapped.
Type: Character
Optional Arguments
icon
specifies the icon to display in the message window:
'I'
Information or note icon (default)
'?'
Query icon
'!'
Warning icon
'S'
Error icon (stop sign/hand)
Type: Character
buttons
specifies the set of command buttons to display in the message window:
'O'
Ok (default)
'OC'
Ok, Cancel
'YN'
Yes, No
'YNC'
Yes, No, Cancel
'YYNC'
Yes, Yes to all, No, Cancel
'ARI'
Abort, Retry, Ignore
'RAC'
Replace, Append, Cancel
'RC'
Retry, Cancel
Type: Character
caption
the title for the message window.
Type: Character
default
specifies the button that is activated when a user presses Enter in the message
window instead of selecting a button. Default is specified by a single character that
METHOD (execute) 533
corresponds to one of the characters specified in buttons. If default is not supplied,
the default selection is the first button in the message window.
Type: Character
right
specifies whether the text in the message window is right- or left- justified:
'N'
Left justify the text. (default)
'Y'
Right justify the text.
Type: Character
Details
MESSAGEBOXC calls a host message window. If the message window cannot open, or
if text is invalid, the program halts. On hosts that allow users to close the message
window without selecting a button, CANCEL is returned even if it is not one of the
button choices.
Example
The code below creates a window to prompt users to save their changes.
command=messageboxc('Do you want to save your changes?','!','YN','Save?','Y','');
put command;
See Also
“MESSAGEBOX” on page 530
METHOD (execute)
Executes a method block that is defined in an SCL entry
Category:
Modular Programming and Object Oriented
Syntax
CALL METHOD(entry,label<,parameters> );
return-value=METHOD(entry,label<,parameters> );
Required Arguments
entry
is a catalog entry of type SCL. To specify an entry in the current catalog, use entry or
entry.type. To specify an entry in a different catalog, use libref.catalog.entry.type. If
type is not specified, it defaults to SCL.
Type: Character
label
is the name of the method block in the SCL entry.
Type: Character
534
Chapter 13
•
SAS Component Language Dictionary
return-value
contains the value that is returned by the method block.
Type: Numeric, Character, List, Object, Class, or Interface
Optional Argument
parameters
are parameters to pass to the method block. The SCL entry that receives these
parameters must declare each of them in a METHOD statement.
Type: Character
Note
These parameters are update parameters. See “Input, Output, and Update
Parameters” on page 38 for more information.
Details
Passing Parameters
METHOD can pass parameter values to the called method, and it can receive a value
when it is used as a function. To return a value, the associated METHOD statement must
contain the RETURN= option, and the RETURN statement must specify the variable or
literal value to return.
Parameters that are passed must agree with the number of arguments, relative positions,
and data types in the corresponding method block unless the REST= or ARGLIST=
options are used in the method block. The parameter names in METHOD do not have to
match the argument names in the method block.
A method block, which contains a sequence of SCL statements, can be defined either in
the current SCL entry or in another, external SCL entry. If the method block is defined
in the current entry, it is more efficient to use a LINK statement instead of a METHOD
routine.
Parameters are passed in the following ways:
call-by-reference
passes variables and enables values to be returned to CALL METHOD. This
approach enables the called method block to modify values and then to return them.
An example of a call-by-reference is
call method('b.scl','abc',var1,name,field2);
If you do not want to return the values, use the NOCHANGE() routine in the method
block. Or, you can assign the INPUT, OUTPUT, and UPDATE options to the
variables listed in the METHOD statement to determine which variables can receive
and return values. For example:
abc: method var1 :input :num
name :update :char
field1 :output :num;
call-by-value
is used for all numeric constants, character constants, and expressions. It does not
return values to the calling METHOD routine. An example of a call-by-value is
call method('b.scl','abc',100,'hello',x+y);
METHOD (define)
535
Dot Syntax and Passing a Value to CALL METHOD
If you call a method using a CALL METHOD that is defined to return a value, and you
pass that method a parameter that is defined using dot syntax, the value returned from
the method may be 0.
For example, suppose that you define a method named getLength that returns a numeric
value equal to the length of the parameter passed to the method as follows:
getLength: method instring: input: char return=num;
return length(instring);
endmethod;
The method will return a value of 0 (zero) if the parameter passed to the method is
defined using dot syntax. For example:
call method('mylib.myCatalog.myMethod.scl', 'myMethod', _frame_.resource);
To avoid this issue, assign the attribute value you wish to pass to an SCL variable, and
then pass that variable as the parameter. For example:
frameResource=_frame_.resource;
call method('mylib.myCatalog.myMethod.scl', 'myMethod', frameResource);
Example
Call the method block that is labeled ABC in the SCL entry CODE. The following three
parameters are passed: the contents of the variable A, the literal value 3, and the contents
of the variable C.
call method('code.scl', 'abc', a, 3, c);
The method block can return modified values to the variables A and C unless the
NOCHANGE routine is specified in the method block or unless A and C are not
specified in the METHOD statement as input parameters.
See Also
•
“DISPLAY” on page 326
•
“NOCHANGE” on page 566
•
“METHOD (define)” on page 535
METHOD (define)
Defines a method that can be called by the METHOD routine
Category:
Modular Programming and Object Oriented
Syntax
method-name-label:< method-access-scope > METHOD <argument-list>
<OPTIONAL=argument-list>
<ARGLIST=arg-list-id | REST=rest-list-id>
<RETURN=data-type> ;
536
Chapter 13
•
SAS Component Language Dictionary
Required Argument
method-name-label
specifies the method name label, which can be up to 32 characters in length. Method
labels have the same syntax as SCL labels.
CAUTION:
Leading underscores in method names typically identify methods that are
supplied with the SAS System. It is recommended that you do not define
method names that have leading underscores unless the underscores are required.
For example, you may need to create a new component that supports an interface,
such as the staticStringList interface, that has methods that are defined with
leading underscores.
Optional Arguments
method-access-scope
species how the method can be accessed. If the method-access-scope is not provided,
a method has PUBLIC scope. Method-access-scope is valid only for METHOD
statements in a CLASS or USECLASS block.
PUBLIC
specifies that the method can be accessed by any SCL program.
PRIVATE
specifies that the method can be accessed only by methods in the same class in
which the method is defined. Private methods are not inherited by subclasses of
the class.
PROTECTED
specifies that the method can be accessed only by subclasses of the class in
which the method is defined. Because a class can be considered a subclass of
itself, a protected method can also be accessed from the class in which it is
defined.
argument-list
list one or more sets of arguments, with each set specified as follows:varlist:<INPUT|UPDATE|OUTPUT>:data-type(length)
var-list
lists one or more variables to contain values that are passed in from a method call
using either dot notation “Accessing Object Attributes and Methods with Dot
Notation” on page 132, or the METHOD, SEND, SUPER, APPLY or
SUPAPPLY routine or function. Variables can also be a reference array.
Reference array's dimensions are specified by '*'. Comma delimiters are required
to separate '*' for multiple dimensions. The actual size of the reference array will
be determined at run-time based on the dimensions specified in the array
parameter of the calling method. For more information, see “ARRAY” on page
220 and the example “Example 3: Reference Array Whose Size Is Determined at
Run Time” on page 541.
INPUT | I
the values of the caller's parameters are copied into the corresponding parameters
in the called method. When the called method's ENDMETHOD statement is
executed, any updated values are not copied out to the caller's parameters. This is
equivalent to using CALL NOCHANGE() inside the METHOD block.
UPDATE | U
the values of the caller's parameters are copied into the corresponding parameters
in the called method. When the called method's ENDMETHOD statement is
METHOD (define)
537
executed, any updated values are copied out to the caller's parameters (unless
CALL NOCHANGE is specified). An error condition results if the corresponding
parameter in the calling program is a constant, because a constant cannot receive
a value. All Version 6 SCL method parameters are UPDATE parameters.
OUTPUT | O
this storage type serves as an indication in the code that only the returned value is
significant, despite the fact that the input parameter might change. Functionally,
the output type is the same as update type.
data-type
specifies the type of data that the variable will contain. A named data type (for
example, CHAR or LIST) must be preceded by the : delimiter. The delimiter is
optional for unnamed data types (for example, $).
CHAR<(length)>
specifies that the variable will contain character data. Length can be 1 to
32,767 characters. If length is not provided, the default length is 200.
Note
You cannot specify length for the CHAR data-type within the
RETURN option.
LIST
specifies that the variable will contain an SCL list identifier.
NUM
specifies that the variable will contain a numeric value.
OBJECT
specifies that the variable will contain the identifier for an object when it is
defined at run time.
This type causes the SCL compiler to generate extra conversion instructions.
Consequently, you should use it only when necessary so as to achieve
optimal run-time performance.
class-name
specifies that the variable will contain the identifier for an object of the class
specified in class-name. This type of object is defined at compile time. Classname must be a three- or four-level name unless an IMPORT statement has
specified the libref and catalog. In that case, the name can be a one- to fourlevel name. If the entry type is not specified, it is assumed to be CLASS.
interface-name
specifies that the variable will contain the identifier for an object of the class
that supports the interface specified in interface-name. Interface-name must
be a three- or four-level name unless an IMPORT statement has been used to
specify the libref and catalog. In that case, the name can be a one- to fourlevel name.
If the entry type is not specified and a class with that name does not exist, the
default entry type of INTERFACE is assumed.
To be compatible with the applications built in earlier releases of SAS software,
the : delimiter is optional for variables that are declared with unnamed data types
(for example, $), but it is required for variables that are assigned named data
types. The following example shows a variety of data type declarations including
the reference arrays using * as the dimensions:
mymethod: method
char1 : Char(20)
char2 : Char(10)
538
Chapter 13
•
SAS Component Language Dictionary
char3 :input :char(50)
charArr(*):u:char /* a reference array */
num1
: Num
num2
: Num
num3
: num
numArr(*):num
/* a reference array */
myList :list
myObj :object
myCol :sashelp.fsp.Collection.class ;
Type: Character
length
is a numeric constant that specifies the length of the preceding variable or
variables. The length of a character variable does not have to match the length of
the corresponding passed parameter. SCL pads or truncates as necessary. When a
length is specified for a variable that is declared as CHAR, the length
specification must be enclosed in parentheses.
Type: Character
arg-list-id
contains the identifier for the SCL list that will contain all the arguments passed to
the method. This includes all optional arguments.
Type: List
rest-list-id
contains the identifier for the SCL list that will contain all arguments that are passed
to the method but are not explicitly specified in argument-list for either METHOD or
OPTIONAL=.
Type: List
data-type
specifies the type of data that the method can return. The valid data types are Num,
Char, List , Object , Array, and Class types.
Details
Introduction
The METHOD statement enables you to create method blocks and methods for SAS/AF
classes. A method block is a feature for defining methods or for making a frequently
used routine available to other programs. Methods define the actions for a class. A
method block starts with the METHOD labels and ends with an ENDMETHOD
statement. Only SCL entries can contain method blocks. Each method block contains
additional SCL statements.
RETURN=data-type enables you to return a value to the calling method. An error
condition is produced if data-type is not the same as the type of data to be returned to the
calling program. Use a RETURN statement in the method to specify the value to return.
In SCL CLASS statement block or USECLASS statement block, each METHOD
statement starts a new local variable scope just like an SCL DO/END block. Parameters
with the same name but with the different types can be used across different method
statements.
The METHOD statement receives parameters from the calling routine. When there are
no optional arguments in the METHOD statement, a strict correspondence is required
between the parameters that are passed by the calling routine and the arguments for the
METHOD statement. The arguments and parameters must agree in number, data type,
METHOD (define)
539
and relative position. If the calling program passes an incorrect number of parameters or
a parameter of an incorrect type, SCL stops executing the program. The argumentparameter correspondence is less restrictive when you use the options OPTIONAL=,
ARGLIST=, and REST= in the METHOD statement:
OPTIONAL=
enables you to specify one or more optional arguments that are used only if the
calling program supplies the corresponding parameters in the parameter list of the
calling routine. If corresponding parameters are not supplied, then the optional
arguments are initialized to missing values.
ARGLIST= and REST=
enable you to pass a variable number of parameters to the METHOD statement. You
determine the types and order of the variable arguments. The lists identified by arglist-id and rest-list-id are created automatically when the entry is called, and they are
deleted automatically when the entry ends. When an array is passed as a parameter,
the array is expanded into individual items and these items are inserted into the arglist-id and rest-list-id lists. ARGLIST= and REST= are mutually exclusive, so you
can use only one or the other.
Calling and Executing Method Blocks
Other SCL programs call a method block by specifying its label in a dot notation
statement or in a METHOD, APPLY, SUPER, SUPAPPLY, or SEND routine or
function. Execution of the method block starts at the METHOD statement and ends with
the ENDMETHOD statement. After a method block is executed, control returns either to
the calling program statement or to the command line. A method block can be tested
individually by invoking a TESTAF command with the label=method-name option with
the SCL debugger. For example, the following statement tests the COMBINE method:
testaf label=combine
Scope of Method Block Variables
All variables that are declared using the DECLARE statement in a method block are
local to that method. You cannot use a GOTO statement to jump into a method block in
the current entry. All the method parameters are also local to that method if method
blocks are written inside a CLASS statement block or a USECLASS statement block.
Passing Parameters to Method Blocks
The METHOD statement can receive parameter values for variables that are declared as
UPDATE or INPUT. By default, all parameters declared in a METHOD statement are
UPDATE parameters.
The parameter-receiving mechanism for the METHOD statement is very similar to that
mechanism for the ENTRY statement. The METHOD statement receives parameters
from the third argument of the calling METHOD routine. The calling METHOD routine
must agree with the corresponding METHOD statement in the following ways (unless
OPTIONAL=, ARGLIST=, or REST= are specified):
•
The number of arguments received must be the same as the number of parameters
passed.
•
The relative positions of the arguments passed must match the parameters in the
corresponding METHOD statement.
•
The data types of both sets of variables must agree.
Otherwise, SCL stops executing the calling METHOD routine and prints an error
message.
540
Chapter 13
•
SAS Component Language Dictionary
Returning Modified Parameters to the Calling Routine
The METHOD statement can return values to parameters from variables that are
declared as UPDATE or OUTPUT. A called method block can modify any argument it
receives. However, it cannot return new values to calling routine parameters that are
numeric literals, character literals, or expressions. By default, values for variables are
returned to the calling routine. If you want a called method block to receive values but
not to return values to its calling routine, declare the variables as INPUT. If you want
variables in the method to only return values, then declare the method's variables as
OUTPUT.
For more information, see “What Happens When Attribute Values Are Set or Queried”
on page 135.
Returning a Value to the Calling Routine
A METHOD statement can return a value to the calling routine when the METHOD
statement uses the RETURN= option to declare the data type of the returned value. A
RETURN statement in the method specifies either the variable or expression that
contains the value or the literal value to return.
Examples
Example 1: METHOD Statement Declarations
Method M1 contains a variety of argument specifications.
IMPORT work.myclass.collection.class;
Class Example1;
M1: PUBLIC METHOD
/* usenum is UPDATE (default) numeric
usenum :NUM
/* usechar is UPDATE (default) character
usechar :CHAR
/* mylist is UPDATE (default) list
mylist :LIST
/* myobject is UPDATE (default) object
myobject :OBJECT
/* mycoll is UPDATE (default) collection
mycoll :COLLECTION
/* innum is INPUT numeric
innum :INPUT :NUM
/* state is OUTPUT character
state :OUTPUT :CHAR
/* namelist is UPDATE list
namelist :UPDATE :LIST
/* outputobj is OUTPUT object
outputobj :OUTPUT :OBJECT
/* amountin is INPUT numeric
amountin :I :NUM
/* c3 is OUTPUT character
c3 :O :CHAR
/* l3 is UPDATE list
l3 :U :LIST
/* numarr is a numeric UPDATE array
numarr(5) : NUM
/* states is a character reference array
states(*) : CHAR
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
METHOD (define)
541
/* return a numeric value
*/
RETURN=NUM;
...SCL statements that define the method...
RETURN(0);
ENDMETHOD;
EndClass;
Example 2: Using the RETURN= Option
Define an ADD method to add the numbers stored in N1 and N2, and return the sum in
the variable TOTAL:
Class Example2;
add: public method n1:num n2:num return=num;
total=n1+n2;
return(total);
endmethod;
EndClass;
Example 3: Reference Array Whose Size Is Determined at Run Time
The following Sort class contains two overloaded methods that are named SORT. Each
method contains an array parameter that is a reference array. The size of the reference
array will be determined at run time based on the associated array parameters in the
calling methods.
Class Sort;
/* Generic sort routine for any size of */
/* 1-dimensional numeric array */
sort: method narr(*):Num;
/* Find dimensions from the calling program */
DCL Num temp i j;
DCL Num size = dim(narr);
/* --- Bubble Sort --- */
do i = 1 to size - 1;
do j = i+1 to size;
if narr(i) > narr(j) then
do;
temp = narr(i);
narr(i) = narr(j);
narr(j) = temp;
end;
end;
end;
/* Array narr is now sorted in ascending order */
endmethod;
/* Generic sort routine for any size of */
/* 1-dimensional character array */
sort: method carr(*):Char;
/* Find dimensions from the calling program */
DCL Char tempc;
DCL Num i j size = dim(carr);
/* --- Bubble Sort --- */
do i = 1 to size - 1;
do j = i+1 to size;
if carr(i) > carr(j) then
do;
tempc = carr(i);
542
Chapter 13
•
SAS Component Language Dictionary
carr(i) = carr(j);
carr(j) = tempc;
end;
end;
end;
/* Array carr is now sorted in ascending order */
endmethod;
EndClass;
Example 4: Calling a Method
This example creates a new instance of the Sort class and sends a message to the sort
method to sort the order of the existing arrays CARR and NARR.
Init:
DCL Char(20) carr(3)=('c','b','a');
DCL Num narr(3)={3, 2, 1};
DCL Sort obj1 = _NEW_ Sort(narr);
DCL Sort obj2 = _NEW_ Sort(carr);
put carr= narr=;
return;
The output is
carr=
carr[1]='a'
carr[2]='b'
carr[3]='c'
narr[1] = 1
narr[2] = 2
narr[3] = 3
Example 5: Using the REST= Argument
Add a variable number of numbers, and print out the sum. The method ignores any
character types that are passed in. When using a variable number of arguments, do not
generate a signature for the method.
class varying;
sumPrint: method msg:Char rest=rest_list/(signature='N');
DCL num totsum valn i;
DCL char type;
if rest_list=. then
do;
put 'No numbers to add were passed in!';
return;
end;
totsum=0;
do i=1 to listlen(rest_list);
type=itemtype(rest_list,i);
if type='N' then
do;
valn=getitemn(rest_list,i);
totsum=totsum+valn;
end;
end;
put msg totsum;
endmethod;
endclass;
_METHOD_ 543
Use the following program to invoke the SUMPRINT method:
init:
DCL varying obj = _NEW_ Varying();
obj.SUMPRINT('The total is:', 30, 15, 1);
return;
The output of this example is
The total is: 46
Example 6: Parameter Scope and Method Variable Scope
This program shows the parameters of the same name and different types being used
across different method statements.
Class ReUseName;
m1: Method n:Num c:Char;
DCL Num localN;
DCL Char localC;
EndMethod;
m2: Method n:Char c:num;
DCL Char localN;
DCL Num localC;
EndMethod;
EndClass;
See Also
“IMPORT” on page 466
_METHOD_
Contains the name of the method that is currently executing
Category:
System Variable
Details
_METHOD_ is a character system variable that is provided automatically by the
FRAME entry in SAS/AF. However, the SCL compiler does not automatically create a
space for it in the SCL data vector. As a result, you get a warning when you compile a
FRAME or SCL entry that uses _METHOD_, because the variable is being referenced at
compile time but is not assigned a value until run time. You can safely ignore this
warning. If you prefer to prevent the warning message from being generated, use the
following assignment statement at the top of your program:
_method_=_method_;
_METHOD_ is useful when you have one or more methods that share the same section
of code but which require a CALL SUPER.
In order to use _METHOD_, you must use the DECLARE or LENGTH statement to
declare it as a character variable.
_METHOD_ has a valid value only when a method is executing.
544
Chapter 13
•
SAS Component Language Dictionary
Example
For a window control, you may define the _update and _bupdate methods to execute the
same section of code if they perform similar functions:
length _method_ $40;
BUPDATE:
UPDATE:
method;
...code for _update and _bupdate methods...
call super(_self_, _method_);
endmethod;
Without _METHOD_, you would not know which method to do a CALL SUPER on, so
you would have to code the above as
BUPDATE:
method;
methodName = '_bupdate';
link update1;
endmethod;
UPDATE:
method;
methodName = '_update';
link update1;
endmethod;
UPDATE1:
...code for _update and _bupdate goes here...
call super(_self_, methodName);
return;
See Also
•
“_SELF_” on page 648
•
“SUPER” on page 688
•
“_VALUE_” on page 711
MLENGTH
Returns the maximum length of a variable
Category:
Character
Syntax
length=MLENGTH(var);
Required Arguments
length
contains the maximum length of a variable.
Type: Numeric
MODIFIED
545
var
is the variable whose maximum length you want to determine.
Type: Character
Details
MLENGTH is different from LENGTH, which returns the trimmed length. For window
variables, MLENGTH returns the length of the variable in the display.
If a numeric variable is passed to MLENGTH, MLENGTH always returns a length of 8
for the variable. For non-window variables, MLENGTH returns the declared length of
the variable.
Example
In this example, MLENGTH returns the value 5, which is the declared length of variable
S. However, LENGTH returns the value 2, because S contains ab.
length s $ 5;
s='ab';
l=length(s);
m=mlength(s);
See Also
“LENGTH (return string length)” on page 499
MODIFIED
Reports whether a field or FRAME entry control has been modified
Category:
Control or Field
Syntax
rc=MODIFIED(wcol-name);
Required Arguments
rc
contains the return code for the operation:
1
modified
0
not modified
Type: Numeric
wcol-name
is the name of the field or FRAME entry control in the window. This name cannot be
an element of an array nor an expression. If wcol-name is invalid, the program halts.
Type: Character
546
Chapter 13
•
SAS Component Language Dictionary
Details
A field's state changes to modified when a user types any character in the field and
presses ENTER or a function key or selects a FRAME entry control.
The field or FRAME entry control cannot be an element of an array. To report this
information for an array element, use FIELD instead.
The ERRORON statement causes MODIFIED to return a value of 1.
FRAME entry controls can also use the _isModified method.
Examples
Example 1: Opening an FSEDIT Window
Open an FSEDIT window for the SAS table specified in the TBLNAME variable. The
FSEDIT function displays the table for interactive editing.
if (modified(tblname) and tblname ne ' ' ) then
call fsedit(tblname);
else
_msg_='Please enter a valid table name.';
Example 2: Invalid Syntax for MODIFIED
The following are examples of invalid syntax that will not compile:
/* A literal string is used. */
rc=modified('xyz');
/* Concatenation of two columns. */
rc=modified(a||b);
/* An array element is used. */
rc=modified(a{i});
See Also
•
“DISPLAYED” on page 329
•
“ERROR” on page 352
•
“ERROROFF” on page 353
•
“ERRORON” on page 354
•
“FIELD” on page 373
•
“OBSINFO” on page 573
MODVAR
Changes the name, label, format, or informat of a column in a SAS table
Category:
Variable
Syntax
sysrc=MODVAR(table-id,var-name,new-name<,label <,format<,informat> > > );
MODVAR
547
Required Arguments
sysrc
contains the return code for the operation:
0
successful
≠0
not successful
Type: Numeric
table-id
is the identifier that was assigned when the table was opened. If table-id is invalid,
the program halts.
Type: Numeric
var-name
is the column whose attribute or attributes you want to change. The column must
already exist in the SAS table.
Type: Character
new-name
is the new name to assign to the column. The value must be a valid SAS name and
cannot already exist in the SAS table.
Type: Character
Optional Arguments
label
is the label to assign to the column.
Type: Character
format
is the format to assign to the column.
Type: Character
informat
is the informat to assign to the column.
Type: Character
Details
The table must be opened in UTILITY (V) mode, or the function halts.
If you do not want to change an argument, insert a null string ('') as a placeholder.
Example
Change only the label for the column PHONENUM in the SAS table CUSTOMR:
dsid=open('customr','v');
if dsid then
do;
rc=modvar(dsid,'phonenum','','Office Phone');
rc=close(dsid);
end;
548
Chapter 13
•
SAS Component Language Dictionary
See Also
•
“OPEN” on page 574
•
“VARFMT” on page 712
•
“VARINFMT” on page 713
•
“VARLABEL” on page 714
•
“VARLEN” on page 715
•
“VARNAME” on page 720
•
“VARNUM” on page 721
•
“VARTYPE” on page 724
MOPEN
Opens a member file in a directory
Category:
Directory
Syntax
file-id=MOPEN(directory-id,member-name<open-mode <,record-length<,record-format> > > );
Required Arguments
file-id
contains the identifier for the file, or 0 if the file could not be opened. You can use a
file-id that is returned by the MOPEN function just as you would use a file-id
returned by the FOPEN function.
Type: Numeric
directory-id
is the identifier that was returned by DOPEN when the directory was opened. If
directory-id is invalid, the program halts.
Type: Numeric
member-name
is the name of a file in the directory that is identified by directory-id.
Type: Character
Optional Arguments
open-mode
is the type of access to the file:
'A'
APPEND mode, which allows writing new records after the current end of
the file.
'I'
INPUT mode, which allows reading only. (This is the default.)
'O'
OUTPUT mode, which defaults to the OPEN mode that was specified in
host-options in the FILENAME statement or function. If no host option
MOPEN 549
was specified, then OUTPUT mode allows writing new records at the
beginning of the file.
'S'
Sequential input mode, which is used for pipes and other sequential
devices such as hardware ports.
'U'
UPDATE mode, which allows both reading and writing.
Type: Character
record-length
is the logical record length of the file. To use the existing record length for the file,
specify a length of 0 or do not provide a value here.
Type: Numeric
record-format
is the record format of the file:
'B'
Interpret data as binary data.
'D'
Use the default record format.
'E'
Use an editable record format.
'F'
The file contains fixed-length records.
'P'
The file contains printer carriage-control characters in a host-dependent
record format.
'V'
The file contains variable-length records.
To use the existing record format, do not specify a value here.
Type: Character
Details
CAUTION:
Use OUTPUT mode with care. Opening an existing file for output may overwrite
the current contents of the file without warning.
The member file is identified by directory-id and member-name instead of by a fileref.
You can als