{Begin SubSec Loading Files} {Title Loading Files} {Text The functions below load information from symbolic files into the Interlisp environment. A symbolic file contains a sequence of Interlisp expressions that can be evaluated to establish specified typed definitions. The expressions on symbolic files are read using {var FILERDTBL}{index FILERDTBL Var} as the readtable. The loading functions all have an argument {arg LDFLG}. {arg LDFLG} affects the operation of {fn DEFINE}, {fn DEFINEQ}, {fn RPAQ}, {fn RPAQ?}, and {fn RPAQQ}. While a source file is being loaded, {index DFNFLG Var}{var DFNFLG} ({PageRef Var DFNFLG}) is rebound to {arg LDFLG}. Thus, if {arg LDFLG}={lisp NIL}, and a function is redefined, a message is printed and the old definition saved. If {arg LDFLG}={lisp T}, the old definition is simply overwritten. If {arg LDFLG}={lisp PROP}, the functions are stored as "saved" definitions on the property lists under the property {index EXPR Prop}{prop EXPR} instead of being installed as the active definitions. If {arg LDFLG}={lisp ALLPROP},{index ALLPROP Litatom} not only function definitions but also variables set by {index RPAQQ FN}{fn RPAQQ}, {index RPAQ FN}{fn RPAQ}, {index RPAQ? FN}{fn RPAQ?} are stored on property lists (except when the variable has the value {index NOBIND Litatom}{lisp NOBIND}, in which case they are set to the indicated value regardless of {var DFNFLG}). Another option is available for users who are loading systems for others to use and who wish to suppress the saving of information used to aid in development and debugging. If {arg LDFLG}={lisp SYSLOAD},{index *PRIMARY* SYSLOAD (LOAD option)} {fn LOAD} will: (1) Rebind {var DFNFLG} to {lisp T}, so old definitions are simply overwritten; (2) Rebind {var LISPXHIST} to {lisp NIL}, thereby making the {fn LOAD} not be undoable and eliminating the cost of saving undo information (See {PageRef Tag Undoing}); (3) Rebind {var ADDSPELLFLG}{index ADDSPELLFLG Var} to {lisp NIL}, to suppress adding to spelling lists; (4) Rebind {var FILEPKGFLG}{index FILEPKGFLG Var} to {lisp NIL}, to prevent the file from being "noticed" by the file package; (5) Rebind {var BUILDMAPFLG}{index BUILDMAPFLG Var} to {lisp NIL}, to prevent a file map from being constructed; (6) After the load has completed, set the {index filecoms}filecoms variable and any {index filevars}filevars variables{foot A filevars variable is any variable appearing in a file package command of the form {lisp ({arg FILECOM} * {arg VARIABLE})} (see {PageRef Tag FileVars}). Therefore, if the filecoms includes {lisp (FNS * FOOFNS)}, {lisp FOOFNS} is set to {lisp NOBIND}. If the user wants the value of such a variable to be retained, even when the file is loaded with {arg LDFLG}={lisp SYSLOAD},{index SYSLOAD (LOAD option)} then he should replace the variable with an equivalent, {it non-atomic} expression, such as {lisp (FNS * (PROGN FOOFNS))}. }{comment endfootnote} to {lisp NOBIND}; and (7) Add the file name to {var SYSFILES}{index SYSFILES Var} rather than {var FILELST}.{index FILELST Var} Note: All functions that have {arg LDFLG} as an argument perform spelling correction using {index LOADOPTIONS Var}{var LOADOPTIONS} as a spelling list when {arg LDFLG} is not a member of {var LOADOPTIONS}.{index spelling lists} {var LOADOPTIONS} is initially {lisp (NIL T PROP ALLPROP SYSLOAD)}. {FnDef {FnName LOAD} {FnArgs FILE LDFLG PRINTFLG} {Text Reads successive expressions from {arg FILE} (with {var FILERDTBL}{index FILERDTBL Var} as readtable) and evaluates each as it is read, until it reads either {lisp NIL}, or the single atom {lisp STOP}.{index STOP (at the end of a file)} Note that {fn LOAD} can be used to load both symbolic and compiled files. Returns {arg FILE} (full name). If {arg PRINTFLG}={lisp T}, {fn LOAD} prints the value of each expression; otherwise it does not. }} {FnDef {FnName LOAD?} {FnArgs FILE LDFLG PRINTFLG} {Text Similar to {fn LOAD} except that it does not load {arg FILE} if it has already been loaded, in which case it returns {lisp NIL}. Note: The test is whether the root name of {arg FILE} has a {prop FILEDATES} property ({PageRef Prop FILEDATES}). }} {note {fn LOADFNS} was originally written by J. W. Goodwin, and subsequently modified by W. Teitelman.} {FnDef {FnName LOADFNS} {FnArgs FNS FILE LDFLG VARS} {Text Permits selective loading of definitions. {arg FNS} is a list of function names, a single function name, or {lisp T}, meaning to load all of the functions on the file. {arg FILE} can be either a compiled or symbolic file. If a compiled definition is loaded, so are all compiler-generated subfunctions. The interpretation of {arg LDFLG} is the same as for {fn LOAD}. If {arg FILE}={lisp NIL}, {fn LOADFNS} will use {fn WHEREIS} ({PageRef Fn WHEREIS}) to determine where the first function in {arg FNS} resides, and load from that file. Note that the file must previously have been "noticed" (see {PageRef Tag NoticingFiles}). If {fn WHEREIS} returns {lisp NIL}, and the WHEREIS package ({PageRef Tag WHEREISPackage}) has been loaded, {fn LOADFNS} will use the WHEREIS data base to find the file containing {arg FN}. {note I think this is awfully complicated as text. Should probably be done as a vertical list. Next time around, I'll try to reorganize so that it makes more sense. Also, there is a GETDEF option that should be described. I think GETDEF means that the expressions should be returned as the value of LOADFNS, isntead of being evaluated to actually install the defintions} {arg VARS} specifies which non-{fn DEFINEQ} expressions are to be loaded (i.e., evaluated): {lisp T} means all, {lisp NIL} means none, {lisp VARS} means to evaluate all variable assignment expressions (beginning with {fn RPAQ}, {fn RPAQQ}, or {fn RPAQ?}, see {PageRef Fn RPAQ}), and any other atom is the same as specifying a list containing that atom. {note doc flushed: FNS/VARS is the same as (COMS BLOCKS)} If {arg VARS} is a list, each element in {arg VARS} is "matched" against each non-{fn DEFINEQ} expression, and if any elements in {arg VARS} "match" successfully, the expression is evaluated. "Matching" is defined as follows: If an element of {arg VARS} is an atom, it matches an expression if it is {fn EQ} to either the {fn CAR} or the {fn CADR} of the expression. If an element of {arg VARS} is a list, it is treated as an edit pattern ({PageRef Tag EditPattern}), and matched with the entire expression (using {fn EDIT4E}, {PageRef Fn EDIT4E}). For example, if {arg VARS} was {lisp (FOOCOMS DECLARE: (DEFLIST & (QUOTE MACRO)))}, this would cause {lisp (RPAQQ FOOCOMS {ellipsis})}, all {lisp DECLARE:}s, and all {fn DEFLIST}s which set up {lisp MACRO}s to be read and evaluated. If {arg VARS} is a list and {lisp (FNTYP {arg VARS})} is true ({arg VARS} is a function definition), then {fn LOADFNS} will invoke that function on every non-{fn DEFINEQ} expression being considered, applying it to two arguments, the first and second elements in the expression. If the function returns {lisp NIL}, the expression will be skipped; if it returns a non-{lisp NIL} litatom (e.g. {lisp T}), the expression will be evaluated; and if it returns a list, this list is evaluated instead of the expression. Note: The file pointer is set to the very beginning of the expression before calling the {arg VARS} function definition, so it may read the entire expression if necessary. If the function returns a litatom, the file pointer is reset and the expression is {fn READ} or {fn SKREAD}. However, the file pointer is not reset when the function returns a list, so the function must leave it set immediately after the expression that it has presumably read. {note in the case of function definition VARS returning a list, why doesn't it just reset the fileptr and do a SKREAD??} {fn LOADFNS} returns a list of: (1) The names of the functions that were found; (2) A list of those functions not found (if any) headed by the litatom {index NOT-FOUND: Litatom}{atom NOT-FOUND:}; (3) All of the expressions that were evaluated; (4) A list of those members of {arg VARS} for which no corresponding expressions were found (if any), again headed by the litatom {atom NOT-FOUND:}. For example, {lispcode _ (LOADFNS '(FOO FIE FUM) {arg FILE} NIL '(BAZ (DEFLIST &))) (FOO FIE (NOT-FOUND: FUM) (RPAQ BAZ {ellipsis}) (NOT-FOUND: (DEFLIST &)))} {Begin Note} I think that this could all be helped if we didn't talk about "loading" or "evaluating" an expression, but instead said something like "selecting" an expression. LOADFNS operates by selecting from the file a bunch of expressions that satisfy certain properties. Usually, these expressions are evaluated and presumably install various definitions. However if (something) is GETDEF, the lsit of selected expressions is simply returned as the value of LOADFNS ---rmk if LDFLG is GETDEF or EXPRESSIONS, the expressions will not be evaluated, but the selected expressions will always be returned. I am not sure what else these LDFLG options will do, so I am not documenting them yet ---mjs {End Note} }} {FnDef {FnName LOADVARS} {FnArgs VARS FILE LDFLG} {Text Same as {lisp (LOADFNS NIL {arg FILE} {arg LDFLG} {arg VARS})}. }} {FnDef {FnName LOADFROM} {FnArgs FILE FNS LDFLG} {Text Same as {lisp (LOADFNS {arg FNS} {arg FILE} {arg LDFLG} T)}. }} Once the file package has noticed a file, the user can edit functions contained in the file without explicitly loading them. Similarly, those functions which have not been modified do not have to be loaded in order to write out an updated version of the file. Files are normally noticed (i.e., their contents become known to the file package; see {PageRef Tag NoticingFiles}) when either the symbolic or compiled versions of the file are loaded. If the file is {it not} going to be loaded completely, the preferred way to notice it is with {fn LOADFROM}. Note that the user can also load some functions at the same time by giving {fn LOADFROM} a second argument, but it is normally used simply to inform the file package about the existence and contents of a particular file. {note LOADEF doc flushed --- mjs LOADDEFS with type FNS does essentially the same thing, and the confusion of names isn't really worth it. I'm for de-documenting it, if not de-implementing it. ---rmk} {FnDef {FnName LOADBLOCK} {FnArgs FN FILE LDFLG} {Text Calls {fn LOADFNS} on those functions contained in the block declaration containing {arg FN} (See {PageRef Tag BlockDeclarations}). {fn LOADBLOCK} is designed primarily for use with symbolic files, to load the {lisp EXPR}s for a given block. It will not load a function which already has an in-core {lisp EXPR} definition, and it will not load the block name, unless it is also one of the block functions. }} {FnDef {FnName LOADCOMP} {FnArgs FILE LDFLG} {Text Performs all operations on {arg FILE} associated with compilation, i.e. evaluates all expressions under a {lisp DECLARE: EVAL@COMPILE} (see {PageRef FileCom DECLARE:}), and "notices" the function and variable names by adding them to the lists {var NOFIXFNSLST}{index NOFIXFNSLST Var} and {var NOFIXVARSLST}{index NOFIXVARSLST Var} (see {PageRef Var NOFIXVARSLST}). Thus, if building a system composed of many files with compilation information scattered among them, all that is required to compile one file is to {fn LOADCOMP} the others. }} {FnDef {FnName LOADCOMP?} {FnArgs FILE LDFLG} {Text Similar to {fn LOADCOMP}, except it does not load if file has already been loaded, in which case its value is {lisp NIL}. }} {Begin Note} Date: 26 SEP 1979 2159-PDT From: TEITELMAN Subject: changes to loadfns-vars when you are doing a loadcomp or loadcomp?, it only evaluates things in a declare: where EVAL@COMPILE is specified. if you say DONTEVAL@COMPILE, it does not descend. if you are doing a loadvars, it evaluaes thngs in a declare: if you say EVAL@LOAD (or leave it out since thats the default, but if you say DONTEVAL@LOAD it doesnt). when doing a loadcop, the tags EVAL@LOAD DONTEVAL@LOAD are totally ignored. when doing a loadfns/vars the tags eval@compile, donteval@compile are ignored. note that the expressions are evaluated as well as being put on donelst and returned. i think this captures the semantics. the reason loadfrom used to work was that it simply evaluated the entire top level (DECLARE: expression) i.e. never searched inside it, so the tags hhd the right effect, i.e. with a DONTEVAL@LOAD, it stopped. with loadfns or loadvars want to sarch for a specific expression, and so should be guided in a similar way by the tags. {End Note} }{End SubSec Loading Files} {Begin SubSec Storing Files} {Title Storing Files} {Text {FnDef {FnName MAKEFILE} {FnArgs FILE OPTIONS REPRINTFNS SOURCEFILE} {Text Makes a new version of the file {arg FILE}, storing the information specified by {arg FILE}'s filecoms. Notices {arg FILE} if not previously noticed (see {PageRef Tag NoticingFiles}). Then, it adds {arg FILE} to {index NOTLISTEDFILES Var}{var NOTLISTEDFILES}{foot Except if {arg FILE} has on its property list the property {prop FILETYPE} with value {lisp DON'TLIST}, or a list containing {lisp DON'TLIST}. }{comment endfootnote} and {index NOTCOMPILEDFILES Var}{var NOTCOMPILEDFILES}.{foot Except if {arg FILE} has on its property list the property {prop FILETYPE} with value {lisp DON'TCOMPILE}, or a list containing {lisp DON'TCOMPILE}. Also, if {arg FILE} does not contain any function definitions, it is not added to {var NOTCOMPILEDFILES},{index NOTCOMPILEDFILES Var} and it is not compiled even when {arg OPTIONS} specifies {lisp C} or {lisp RC}. }{comment endfootnote} {arg OPTIONS} is a litatom or list of litatoms which specify options. By specifying certain options, {fn MAKEFILE} can automatically compile or list {arg FILE}. Note that if {arg FILE} does not contain any function definitions, it is not compiled even when {arg OPTIONS} specifies {lisp C} or {lisp RC}. The options are spelling corrected using the list {var MAKEFILEOPTIONS}{index MAKEFILEOPTIONS Var}. If spelling correction fails, {fn MAKEFILE} generates an error. The options are interpreted as follows: {Begin LabeledList interpretation of OPTIONS} {Indent 20percent} {Label {lisp C}{index *PRIMARY* C (MAKEFILE option)}} {Label {lisp RC}{index *PRIMARY* RC (MAKEFILE option)}} {Text After making {arg FILE}, {fn MAKEFILE} will compile {arg FILE} by calling {fn TCOMPL} (if {lisp C} is specified) or {fn RECOMPILE} (if {lisp RC} is specified). If there are any block declarations specified in the filecoms for {arg FILE}, {fn BCOMPL} or {fn BRECOMPILE} will be called instead. If {lisp F}, {lisp ST}, {lisp STF}, or {lisp S} is the {it next} item on {arg OPTIONS} following {lisp C} or {lisp RC}, it is given to the compiler as the answer to the compiler's question {lisp LISTING?} (see {PageRef Tag CompilerQuestions}). For example, {lisp (MAKEFILE 'FOO '(C F LIST))} will dump {lisp FOO}, then {fn TCOMPL} or {fn BCOMPL} it specifying that functions are not to be redefined, and finally list the file. } {Label {lisp LIST}{index *PRIMARY* LIST (MAKEFILE option)}} {Text After making {arg FILE}, {fn MAKEFILE} calls {index LISTFILES FN}{fn LISTFILES} to print a hardcopy listing of {arg FILE}. } {Label {lisp CLISPIFY}{index CLISPIFY (MAKEFILE option)}} {Text {fn MAKEFILE} calls {fn PRETTYDEF} with {index CLISPIFYPRETTYFLG Var}{var CLISPIFYPRETTYFLG}={lisp T} (see {PageRef Var CLISPIFYPRETTYFLG}). This causes {index CLISPIFY FN}{fn CLISPIFY} to be called on each function defined as an {lisp EXPR} before it is prettyprinted.{foot Alternatively, if {arg FILE} has the property {prop FILETYPE} with value {lisp CLISP} or a list containing {lisp CLISP}, {fn PRETTYDEF} is called with {var CLISPIFYPRETTYFLG} reset to {lisp CHANGES}, which will cause {fn CLISPIFY} to be called on all functions marked as having been changed. If {arg FILE} has property {lisp FILETYPE} with value {lisp CLISP}, the compiler will {fn DWIMIFY} its functions before compiling them (see {PageRef Tag CompilingCLISP}). }{comment endfootnote} } {Label {lisp NOCLISP}{index *PRIMARY* NOCLISP (MAKEFILE option)}} {Text {fn MAKEFILE} calls {fn PRETTYDEF} with {index PRETTYTRANFLG Var}{var PRETTYTRANFLG}={lisp T} (see {PageRef Var PRETTYTRANFLG}). This causes CLISP translations to be printed, if any, in place of the corresponding CLISP expressions, e.g., iterative statements, record expressions, {lisp PRINTOUT} forms, etc. } {Label {lisp FAST}{index *PRIMARY* FAST (MAKEFILE option)}} {Text {fn MAKEFILE} calls {fn PRETTYDEF} with {var PRETTYFLG}={lisp NIL}{index PRETTYFLG Var} (see {PageRef Var PRETTYFLG}). This causes data objects to be printed rather than prettyprinted, which is much faster. } {Label {lisp REMAKE}{index *PRIMARY* REMAKE (MAKEFILE option)}} {Text {fn MAKEFILE} "remakes" {arg FILE}: The prettyprinted definitions of functions that have not changed are copied from an earlier version of the symbolic file. Only those functions that have changed are prettyprinted. See {PageRef Tag RemakingFiles}. } {Label {lisp NEW}{index *PRIMARY* NEW (MAKEFILE option)}} {Text {fn MAKEFILE} does {it not} remake {arg FILE}. If {index MAKEFILEREMAKEFLG Var}{var MAKEFILEREMAKEFLG}={lisp T} (the initial setting), the default for all calls to {fn MAKEFILE} is to remake. The {lisp NEW} option can be used to override this default. } {End LabeledList interpretation of OPTIONS} {arg REPRINTFNS} and {arg SOURCEFILE} are used when remaking a file, as described on {PageRef Tag RemakingFiles}. {note old manual says that MAKEFILE passes REPRINTFNS and SOURCEFILE straight to PRETTYDEF. Does it do this if option=NEW?? (i.e. can you tell PRETTYDEF to remake the file while you tell MAKEFILE not to??)} }} If a remake is {it not} being performed, {fn MAKEFILE} checks the state of {arg FILE} to make sure that the entire source file was actually {fn LOAD}ed. If {arg FILE} was loaded as a compiled file, {fn MAKEFILE} prints the message {lisp CAN'T DUMP: ONLY THE COMPILED FILE HAS BEEN LOADED}. Similarly, if only some of the symbolic definitions were loaded via {fn LOADFNS} or {fn LOADFROM}, {fn MAKEFILE} prints {lisp CAN'T DUMP: ONLY SOME OF ITS SYMBOLICS HAVE BEEN LOADED}. In both cases, {fn MAKEFILE} will then ask the user if it should dump anyway; if the user declines, {fn MAKEFILE} does not call {fn PRETTYDEF}, but simply returns {lisp ({arg FILE} NOT DUMPED)} as its value. {indexX {Name NOT DUMPED} {Type (returned by MAKEFILE)} {Text {lisp ({arg FILE} NOT DUMPED)} } } {note what does it dump if user says to dump anyways?? It dumps what it can, and leaves holes for what it can't --Ron.} The user can indicate that {arg FILE} must be block compiled together with other files as a unit by putting a list of those files on the property list of each file under the property {index FILEGROUP Prop}{prop FILEGROUP}. If {arg FILE} has a {prop FILEGROUP} property, the compiler will not be called until all files on this property have been dumped that need to be. {fn MAKEFILE} operates by rebinding {var PRETTYFLG}, {var PRETTYTRANFLG}, and {var CLISPIFYPRETTYFLG}, evaluating each expression on {index *PRIMARY* MAKEFILEFORMS Var}{var MAKEFILEFORMS} (under errorset protection), and then calling {fn PRETTYDEF}. The user can add expressions to {var MAKEFILEFORMS} to implement his own options. {FnDef {FnName MAKEFILES} {FnArgs OPTIONS FILES} {Text Performs {lisp (MAKEFILE {arg FILE} {arg OPTIONS})} for each file on {arg FILES} that needs to be dumped. If {arg FILES}={lisp NIL}, {index FILELST Var}{var FILELST} is used. For example, {lisp (MAKEFILES 'LIST)} will make and list all files that have been changed. In this case, if any typed definitions for any items have been defined or changed and they are {it not} contained in one of the files on {var FILELST}, {fn MAKEFILES} calls {fn ADDTOFILES?} to allow the user to specify where these go. {fn MAKEFILES} returns a list of all files that are made. }} {FnDef {FnName CLEANUP} {FnArgs FILE{sub 1} FILE{sub 2} {ellipsis} FILE{sub N}} {Type NOSPREAD NLAMBDA} {Text Dumps, lists, and recompiles (with {fn RECOMPILE}{index RECOMPILE FN} or {index BRECOMPILE FN}{fn BRECOMPILE}) any of the specified files (unevaluated) requiring the corresponding operation. If no files are specified, {index FILELST Var}{var FILELST} is used. {fn CLEANUP} returns {lisp NIL}. {note MIKE: I think cleanupoptions just the list of options that cleanup passes to MAKEFILES and probably thence to MAKEFILE. Perhaps nothing more needs to be said here. Note also that if the first argument to CLEANUP is a list, it isn't interpreted as a filename. Instead, it is used instead of cleanup options to say what should be done. e.g. (CLEANUP (RC F) FUM)} {fn CLEANUP} uses the value of the variable {var CLEANUPOPTIONS}{index *PRIMARY* CLEANUPOPTIONS Var} as the {arg OPTIONS} argument to {fn MAKEFILE}. {var CLEANUPOPTIONS} is initially {lisp (LIST RC)}, to indicate that the files should be listed and recompiled. If {var CLEANUPOPTIONS} is set to {lisp (RC F)}, no listing will be performed, and no functions will be redefined as the result of compiling. Alternatively, if {arg FILE{sub 1}} is a list, it will be interpreted as the list of options regardless of the value of {var CLEANUPOPTIONS}. }} {FnDef {FnName FILES?} {FnArgs } {Text Prints on the terminal the names of those files that have been modified but not dumped, dumped but not listed, dumped but not compiled, plus the names of any functions and other typed definitions (if any) that are not contained in any file. If there are any, {fn FILES?} then calls {fn ADDTOFILES?} to allow the user to specify where these go. }} {FnDef {FnName ADDTOFILES?} {FnArgs {anonarg}} {Text Called from {fn MAKEFILES}, {fn CLEANUP}, and {fn FILES?} when there are typed definitions that have been marked as changed which do not belong to any file. {fn ADDTOFILES?} lists the names of the changed items, and asks the user if he wants to specify where these items should be put. If user answers {lisp N}(o), {fn ADDTOFILES?} returns {lisp NIL} without taking any action. If the user answers {lisp ]}, this is taken to be an answer to each question that would be asked, and all the changed items are marked as dummy items to be ignored. Otherwise, {fn ADDTOFILES?} prints the name of each changed item, and accepts one of the following responses: {Begin LabeledList accepts one of the following responses} {Indent 10percent} {Name A file name or a variable whose value is a list} {Text Adds the item to the corresponding file or list, using {fn ADDTOFILE}. If the item is not the name of a file on {var FILELST}, the user will be asked whether it is a new file. If he says no, then {fn ADDTOFILES?} will check whether the item is the name of a list, i.e. whether its value is a list. If not, the user will be asked whether it is a new list. } {Name line-feed} {Text Same as the user's previous response. } {Name space or carriage return} {Text Take no action. } {Name {lisp ]}} {Text The item is marked as a dummy item by adding it to {var NILCOMS}.{index *PRIMARY* NILCOMS Var} This tells the file package simply to ignore this item. } {Name {lisp [}} {Text The "definition" of the item in question is prettyprinted to the terminal, and then the user is asked again about its disposition. } {Name {lisp (}} {Text {fn ADDTOFILES?} prompts with "{lisp LISTNAME: (}", the user types in the name of a list, i.e. a variable whose value is a list, terminated by a {lisp )}. The item will then only be added to (under) a command in which the named list appears as a filevar. If none are found, a message is printed, and the user is asked again. For example, the user defines a new function {lisp FOO3}, and when asked where it goes, types {lisp (FOOFNS)}. If the command {lisp (FNS * FOOFNS)} is found, {lisp FOO3} will be added to the value of {lisp FOOFNS}. If instead the user types {lisp (FOOCOMS)}, and the command {lisp (COMS * FOOCOMS)} is found, then {lisp FOO3} will be added to a command for dumping functions that is contained in {lisp FOOCOMS}. Note: If the named list is not also the name of a file, the user can simply type it in without parenthesis as described above. } {Name {lisp @}} {Text {fn ADDTOFILES?} prompts with {lisp "Near: ("}, the user types in the name of an object, and the item is then inserted in a command for dumping objects (of its type) that contains the indicated name. The item is inserted immediately after the indicated name. } {End LabeledList accepts one of the following responses} {note these last two options are somewhat unclear. Should I explain more about filevars, or are those archaic. NO: only the list option is somewhat archaic; the @ is very useful. You can have multiple FNS commands on a file, and you can use @ to say which one you want the definition to go on.} }} {FnDef {FnName LISTFILES} {FnArgs FILE{sub 1} FILE{sub 2} {ellipsis} FILE{sub N}} {Type NOSPREAD NLAMBDA} {Text Lists each of the specified files (unevaluated). If no files are given, {index NOTLISTEDFILES Var}{var NOTLISTEDFILES} is used. Each file listed is removed from {index *PRIMARY* NOTLISTEDFILES Var}{var NOTLISTEDFILES} if the listing is completed. For each file not found, {fn LISTFILES} prints the message {lisp "{arg FILENAME} NOT FOUND"} and proceeds to the next file. {fn LISTFILES} calls the function {fn LISTFILES1} on each file to be listed. The user can advise or redefine {fn LISTFILES1} for more specialized applications. {indexX {Name NOT FOUND} {Type (printed by LISTFILES)} {Text {lisp {arg FILENAME} NOT FOUND} } } (Interlisp-10) {fn LISTFILES} uses the function {fn TENEX} ({PageRef Fn TENEX}) to tell the operating system to print the file. {fn LISTFILES} calls {index LISTFILES1 FN}{fn LISTFILES1} which calls {fn TENEX} with {lisp (CONCAT 'LIST$ {arg FILENAME} LISTFILESTR)}, where {var LISTFILESTR} is initially "{CRsymbol}".{index LISTFILESTR Var} The user can reset {var LISTFILESTR} to specify subcommands for the list command, or advise or redefine {fn LISTFILES1}. (Interlisp-D) {fn LISTFILES1} is initially defined as {fn EMPRESS} ({PageRef Fn EMPRESS}). }} {FnDef {FnName COMPILEFILES} {FnArgs FILE{sub 1} FILE{sub 2} {ellipsis} FILE{sub N}} {Type NOSPREAD NLAMBDA} {Text Executes the {lisp RC} and {lisp C} options of {index MAKEFILE FN}{fn MAKEFILE} for each of the specified files (unevaluated). If no files are given, {index *PRIMARY* NOTCOMPILEDFILES Var}{var NOTCOMPILEDFILES} is used. Each file compiled is removed from {var NOTCOMPILEDFILES}. If {arg FILE{sub 1}} is a list, it is interpreted as the {arg OPTIONS} argument to {fn MAKEFILES}. This feature can be used to supply an answer to the compiler's {lisp LISTING?} question, e.g., {lisp (COMPILEFILES (STF))} will compile each file on {var NOTCOMPILEDFILES} so that the functions are redefined without the {lisp EXPR}s definitions being saved. }} {index *PRIMARY* WHEREIS Fn} {FnDef {FnName WHEREIS} {FnArgs NAME TYPE FILES FN} {Text {arg TYPE} is a file package type. {fn WHEREIS} sweeps through all the files on the list {arg FILES} and returns a list of all files containing {arg NAME} as a {arg TYPE}. {fn WHEREIS} knows about and expands all file package commands and file package macros. {arg TYPE}={lisp NIL} defaults to {lisp FNS} (to retrieve function definitions). If {arg FILES} is not a list, the value of {var FILELST} is used. If {arg FN} is given, it should be a function (with arguments {arg NAME}, {arg FILE}, and {arg TYPE}) which is applied for every file in {arg FILES} that contains {arg NAME} as a {arg TYPE}. In this case, {fn WHEREIS} returns {lisp NIL}. {note why not pass TYPE to FN too??? -- I suppose that would be useful; you could use the same function for different types, and have it do different things. On the other hand, you can pass in a function that corresponds to the type. I suppose it doesn't hurt to change the implementation to pass it down. Might as well document it that way, and I'll fix it--Ron} {note need example of how this might be used.} If the WHEREIS package ({PageRef Tag WHEREISPackage}) has been loaded, {fn WHEREIS} is redefined so that {arg FILES}={lisp T} means to use the whereis package data base, so {fn WHEREIS} will find {arg NAME} even if the file has not been loaded or noticed. {arg FILES}={lisp NIL} always means use {var FILELST}. }} {Begin SubSec Remaking a Symbolic File} {Title Remaking a Symbolic File} {Text {Tag RemakingFiles} {index remaking a file} Most of the time that a symbolic file is written using {fn MAKEFILE}, only a few of the functions that it contains have been changed since the last time the file was written. Rather than prettprinting all of the functions, it is often considerably faster to "remake" the file, copying the prettprinted definitions of unchanged functions from an earlier version of the symbolic file, and only prettyprinting those functions that have been changed. {fn MAKEFILE} will remake the symbolic file if the {lisp REMAKE} option is specified. If the {lisp NEW} option is given, the file is not remade, and all of the functions are prettprinted. The default action is specified by the value of {index *PRIMARY* MAKEFILEREMAKEFLG Var}{var MAKEFILEREMAKEFLG}: if {lisp T} (its initial value), {fn MAKEFILE} will remake files unless the {lisp NEW} option is given; if {lisp NIL}, {fn MAKEFILE} will not remake unless the {lisp REMAKE} option is given. Note: If the file has never been loaded or dumped, for example if the filecoms were simply set up in memory, then {fn MAKEFILE} will never attempt to remake the file, regardless of the setting of {var MAKEFILEREMAKEFLG}, or whether the {lisp REMAKE} option was specified. When {fn MAKEFILE} is remaking a symbolic file, the user can explicitly indicate the functions which are to be prettyprinted and the file to be used for copying the rest of the function definitions from via the {arg REPRINTFNS} and {arg SOURCEFILE} arguments to {fn MAKEFILE}. Normally, both of these arguments are defaulted to {lisp NIL}. In this case, {arg REPRINTFNS} will be set to those functions that have been changed since the last version of the file was written. For {arg SOURCEFILE}, {fn MAKEFILE} obtains the full name of the most recent version of the file (that it knows about) from the {prop FILEDATES}{index FILEDATES Prop} property of the file, and checks to make sure that the file still exists and has the same file date as that stored on the {prop FILEDATES} property. If it does, {fn MAKEFILE} uses that file as {arg SOURCEFILE}. This procedure permits the user to {fn LOAD} or {fn LOADFROM} a file in a different directory, and still be able to remake the file with {fn MAKEFILE}. In the case where the most recent version of the file cannot be found, {fn MAKEFILE} will attempt to remake using the {it original} version of the file (i.e., the one first loaded), specifying as {arg REPRINTFNS} the union of all changes that have been made since the file was first loaded, which is obtained from the {prop FILECHANGES}{index FILECHANGES Prop} property of the file. If both of these fail, {fn MAKEFILE} prints the message "{lisp CAN'T FIND EITHER THE PREVIOUS VERSION OR THE ORIGINAL VERSION OF {arg FILE}, SO IT WILL HAVE TO BE WRITTEN ANEW}",{index CAN'T FIND EITHER THE PREVIOUS VERSION ... (Printed by System)} and does not remake the file, i.e. will prettyprint all of the functions. When a remake is specified, {fn MAKEFILE} also checks to see how the file was originally loaded (see {PageRef Tag NoticingFiles}). If the file was originally loaded as a compiled file, {fn MAKEFILE} will automatically call {fn LOADVARS} to obtain those {filecom DECLARE:} expressions that are contained on the symbolic file, but not the compiled file, and hence have not been loaded. If the file was loaded by {fn LOADFNS} (but not {fn LOADFROM}), then {fn LOADVARS} will automatically be called to obtain any non-{lisp DEFINEQ} expressions. Note: Remaking a symbolic file is considerably faster if the earlier version has a {it file map} indicating where the function definitions are located ({PageRef Tag FileMaps}), but it does not depend on this information. }{End SubSec Remaking a Symbolic File} }{End SubSec Storing Files} {Begin SubSec Marking Changes} {Title Marking Changes} {Text {Tag MarkingChanges} The file package needs to know what typed definitions have been changed, so it can determine which files need to be updated. This is done by "marking changes". All the system functions that perform file package operations ({fn LOAD}, {fn TCOMPL}, {fn PRETTYDEF}, etc.), as well as those functions that define or change data, ({fn EDITF}, {fn EDITV}, {fn EDITP}, DWIM corrections to user functions) interact with the file package by marking changes. Also, {it typed-in} assignment of variables or property values is noticed by the file package. (Note that if a program modifies a variable or property value, this is not noticed.) In some cases the marking procedure can be subtle, e.g. if the user edits a property list using {fn EDITP}, only those properties whose values are actually changed (or added) are marked. The various system functions which create or modify objects call {fn MARKASCHANGED} to mark the object as changed. For example, when a function is defined via {fn DEFINE} or {fn DEFINEQ}, or modified via {fn EDITF}, or a DWIM correction, the function is marked as being a changed object of type {lisp FNS}. Similarly, whenever a new record is declared, or an existing record redeclared or edited, it is marked as being a changed object of type {lisp RECORDS}, and so on for all of the other file package types. The user can also call {fn MARKASCHANGED} directly to mark objects of a particular file package type as changed: {FnDef {FnName MARKASCHANGED} {FnArgs NAME TYPE REASON} {Text Marks {arg NAME} of type {arg TYPE} as being changed. {arg REASON} is a litatom that indicated how {arg NAME} was changed. {fn MARKASCHANGED} recognizes the following values for {arg REASON}: {Begin LabeledList MARKASCHANGED recognizes the following values for REASON} {Indent 20percent} {Name {lisp DEFINED}} {Text {index DEFINED (MARKASCHANGED reason)}Used to indicate the creation of {arg NAME}, e.g. from {fn DEFINE}. } {Name {lisp CHANGED}} {Text {index CHANGED (MARKASCHANGED reason)}Used to indicate a change to {arg NAME}, e.g. from the editor. } {Name {lisp DELETED}} {Text {index DELETED (MARKASCHANGED reason)}Used to indicate the deletion of {arg NAME}, e.g. by {fn DELDEF}. {note doing MARKASCHANGED with DELETED will unmarkaschanged and remove from files (unless type=files)} {note example??} } {Name {lisp CLISP}} {Text {index CLISP (MARKASCHANGED reason)}Used to indicate the modification of {arg NAME} by CLISP translation. } {End LabeledList MARKASCHANGED recognizes the following values for REASON} {note Is the following correct?? Yes--Ron. The point is that the change didn't really affect what should appear on the file. note that for some REASONs, MARKASCHANGED may choose not to mark the item as changed. For example, CLISP translation does not signal that a function should be dumped, unless CLISPIFPRETTYFLG=NIL} For backwards compatibility, {fn MARKASCHANGED} also accepts a {arg REASON} of {lisp T} (={lisp DEFINED}) and {lisp NIL} (={lisp CHANGED}). New programs should avoid using these values. {note note though, that the WHENCHANGED fn of a filepkgtype is still passed T or NIL} {fn MARKASCHANGED} returns {arg NAME}. {fn MARKASCHANGED} is undoable. }} {FnDef {FnName UNMARKASCHANGED} {FnArgs NAME TYPE} {Text Unmarks {arg NAME} of type {arg TYPE} as being changed. Returns {arg NAME} if {arg NAME} was marked as changed and is now unmarked, {lisp NIL} otherwise. {fn UNMARKASCHANGED} is undoable. {note in Interlisp-D, seems to always return NIL} }} {FnDef {FnName FILEPKGCHANGES} {FnArgs TYPE LST} {Type NOSPREAD} {Text If {arg LST} is not specified (as opposed to being {lisp NIL}), returns a list of those objects of type {arg TYPE} that have been marked as changed but not yet associated with their corresponding files (See {PageRef Fn UPDATEFILES}). If {arg LST} is specified, {fn FILEPKGCHANGES} sets the corresponding list. {lisp (FILEPKGCHANGES)} returns a list of {it all} objects marked as changed as a list of elements of the form {lisp ({arg TYPENAME} . {arg CHANGEDOBJECTS})}. }} {index EXPR Prop} {index ADVICE Prop} {index MACRO Prop} {index I.S.OPR Prop} Some properties (e.g. {prop EXPR}, {prop ADVICE}, {prop MACRO}, {prop I.S.OPR}, etc..) are used to implement other file package types. For example, if the user changes the value of the property {prop I.S.OPR}, he is really changing an object of type {lisp I.S.OPR}, and the effect is the same as though he had redefined the i.s.opr via a direct call to the function {fn I.S.OPR}. If a property whose value has been changed or added does not correspond to a specific file package type, then it is marked as a changed object of type {lisp PROPS} whose {it name} is {lisp ({arg VARIABLENAME} {arg PROPNAME})} (except if the property name has a property {prop PROPTYPE}{index PROPTYPE Prop} with value {lisp IGNORE}). Similarly, if the user changes a variable which implements the file package type {lisp ALISTS} (as indicated by the appearance of the property {prop VARTYPE}{index VARTYPE Prop} with value {lisp ALIST} on the variable's property list), only those entries that are actually changed are marked as being changed objects of type {lisp ALISTS}, and the "name" of the object will be {lisp ({arg VARIABLENAME} {arg KEY})} where {arg KEY} is {fn CAR} of the entry on the alist that is being marked. If the variable corresponds to a specific file package type other than {lisp ALISTS}, e.g. {lisp USERMACROS}, {lisp LISPXMACROS}, etc., then an object of that type is marked. In this case, the name of the changed object will be {fn CAR} of the corresponding entry on the alist. For example, if the user edits {var LISPXMACROS} and changes a definition for {lisp PL}, then the object {lisp PL} of type {lisp LISPXMACROS} is marked as being changed. }{End SubSec Marking Changes} {Begin SubSec Noticing Files} {Title Noticing Files} {Text {Tag NoticingFiles} {index noticing files} Already existing files are "noticed" by {fn LOAD} or {fn LOADFROM} (or by {fn LOADFNS} or {fn LOADVARS} when the {arg VARS} argument is {lisp T}. New files are noticed when they are constructed by {fn MAKEFILE}, or when definitions are first associated with them via {fn FILES?} or {fn ADDTOFILES?}. Noticing a file updates certain lists and properties so that the file package functions know to include the file in their operations. For example, {fn CLEANUP} will only dump files that have been noticed. The file package uses information stored on the property list of the root name of noticed files. The following property names are used: {PropDef {Name FILE} {Text When a file is noticed, the property {prop FILE}, value {lisp (({arg FILECOMS} . {arg LOADTYPE}))} is added to the property list of its root name. {arg FILECOMS} is the variable containing the filecoms of the file (see {PageRef Tag Filecoms}). {arg LOADTYPE} indicates {it how} the file was loaded, e.g., completely loaded, only partially loaded as with {fn LOADFNS}, loaded as a compiled file, etc. The property {prop FILE} is used to determine whether or not the corresponding file has been modified since the last time it was loaded or dumped. {fn CDR} of the {prop FILE} property records by type those items that have been changed since the last {fn MAKEFILE}. Whenever a file is dumped, these items are moved to the property {prop FILECHANGES},{index FILECHANGES Prop} and {fn CDR} of the {prop FILE} property is reset to {lisp NIL}. }} {PropDef {Name FILECHANGES} {Text The property {prop FILECHANGES} contains a list of all changed items since the file was loaded (there may have been several sequences of editing and rewriting the file). When a file is dumped, the changes in {fn CDR} of the {prop FILE} property are added to the {prop FILECHANGES} property. }} {PropDef {Name FILEDATES} {Text The property {prop FILEDATES} contains a list of version numbers and corresponding file dates for this file. These version numbers and dates are used for various integrity checks in connection with {it re}making a file (see {PageRef Tag RemakingFiles}). }} {PropDef {Name FILEMAP} {Text The property {prop FILEMAP} is used to store the filemap for the file (see {PageRef Tag FileMaps}). This is used to directly load individual functions from the middle of a file. }} {note I stuck in "by type" in the description of FILE property, to vaguely cover the substance of the following notes--Ron} {note Format of FILECHANGES property, and CDR of the FILE property: an alist, where CAR of each element is a file package type, and CDR of each element is a list of those items of that type that have been changed. Note that this is a change: FILECHANGES property and CDR of the FILE property used to be just a list of the changed items, undifferentiated by type.} To compute the root name, {fn ROOTFILENAME}{index ROOTFILENAME Fn} is applied to the name of the file as indicated in the {lisp FILECREATED} expression appearing at the front of the file, since this name corresponds to the name the file was originally made under. The file package detects that the file being noticed is a compiled file (regardless of its name), by the appearance of more than one {lisp FILECREATED} expressions. In this case, each of the files mentioned in the following {lisp FILECREATED} expressions are noticed. For example, if the user performs {lisp (BCOMPL '(FOO FIE))}, and subsequently loads {lisp FOO.DCOM}, both {lisp FOO} and {lisp FIE} will be noticed. When a file is noticed, its root name is added to the list {var FILELST}: {VarDef {Name FILELST} {Text Contains a list of the root names of the files that have been noticed. }} {VarDef {Name LOADEDFILELST} {Text Contains a list of the actual names of the files as loaded by {fn LOAD}, {fn LOADFNS}, etc. For example, if the user performs {lisp (LOAD 'EDITA.COM;3)}, {lisp EDITA} will be added to {var FILELST}, but {lisp EDITA.COM;3} is added to {var LOADEDFILELST}. {var LOADEDFILELST} is not used by the file package; it is maintained solely for the user's benefit. }} }{End SubSec Noticing Files} {Begin SubSec Distributing Change Information} {Title Distributing Change Information} {Text {index updating files} {Tag UPDATEFILES} Periodically, the function {fn UPDATEFILES}{index *PRIMARY* UPDATEFILES FN} is called to find which file(s) contain the elements that have been changed. {fn UPDATEFILES} is called by {fn FILES?}, {fn CLEANUP}, and {fn MAKEFILES}, i.e., any procedure that requires the {prop FILE} property to be up to date. This procedure is followed rather than updating the {prop FILE} property after each change because scanning {var FILELST} and examining each file package command can be a time-consuming process; this is not so noticeable when performed in conjunction with a large operation like loading or writing a file. {fn UPDATEFILES} operates by scanning {var FILELST} and interrogating the file package commands for each file. When (if) any files are found that contain the corresponding typed definition, the name of the element is added to the value of the property {prop FILE} for the corresponding file. Thus, after {fn UPDATEFILES} has completed operating, the files that need to be dumped are simply those files on {var FILELST} for which {fn CDR} of their {prop FILE} property is non-{lisp NIL}. For example, if the user loads the file {lisp FOO} containing definitions for {lisp FOO1}, {lisp FOO2}, and {lisp FOO3}, edits {lisp FOO2}, and then calls {fn UPDATEFILES}, {lisp (GETPROP 'FOO 'FILE)} will be {lisp ((FOOCOMS . T) (FNS FOO2))}. If any objects marked as changed have not been transferred to the {prop FILE} property for some file, e.g., the user defines a new function but forgets (or declines) to add it to the file package commands for the corresponding file, then both {fn FILES?} and {fn CLEANUP} will print warning messages, and then call {fn ADDTOFILES?} to permit the user to specify on which files these items belong. The user can also invoke {fn UPDATEFILES} directly: {FnDef {Name UPDATEFILES} {Args {anonarg} {anonarg}} {Text {lisp (UPDATEFILES)} will update the {prop FILE} properties of the noticed files. {note note: UPDATEFILES has args PRLST, FLST which are only used on calls from subfunction ADDFILE. I assume there is no need to document these args???} }} }{End SubSec Distributing Change Information}